release 1.19.0: domains.conf lang column drives UI i18n default
Per-stack en|fr lives in domains.conf; load_domain_profile sets TALER_DOMAIN_LANG. FP profiles use lang=fr; workstation LANG=en no longer overrides. HTML chrome resolves lang from the same conf.
This commit is contained in:
parent
d664ad0a6e
commit
793e1577b3
7 changed files with 181 additions and 75 deletions
|
|
@ -45,35 +45,110 @@ def atomic_write_text(path: Path, text: str, encoding: str = "utf-8") -> None:
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
def _norm_lang(v: str) -> str:
|
||||
v = (v or "").strip().lower()
|
||||
if v in ("fr", "fra", "french"):
|
||||
return "fr"
|
||||
if v in ("en", "eng", "english"):
|
||||
return "en"
|
||||
return ""
|
||||
|
||||
|
||||
def domain_lang_from_conf(host_hint: str = "") -> str:
|
||||
"""Look up UI lang from domains.conf (suite profile `lang` column).
|
||||
|
||||
Matches host_hint against profile name, bank, exchange, merchant, or
|
||||
canonical fields. Returns '' if no profile matches.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
hint = (host_hint or "").lower()
|
||||
if not hint.strip():
|
||||
return ""
|
||||
|
||||
conf = os.environ.get("TALER_DOMAINS_CONF") or ""
|
||||
candidates = []
|
||||
if conf:
|
||||
candidates.append(Path(conf))
|
||||
# suite root next to site-gen/
|
||||
here = Path(__file__).resolve().parent
|
||||
candidates.append(here.parent / "domains.conf")
|
||||
# cwd / mon root
|
||||
candidates.append(Path("domains.conf"))
|
||||
|
||||
path = next((p for p in candidates if p.is_file()), None)
|
||||
if path is None:
|
||||
return ""
|
||||
|
||||
best = ""
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8", errors="replace")
|
||||
except OSError:
|
||||
return ""
|
||||
|
||||
for raw in text.splitlines():
|
||||
line = raw.split("#", 1)[0].strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split()
|
||||
if len(parts) < 5:
|
||||
continue
|
||||
name, bank, exchange, merchant = parts[0], parts[1], parts[2], parts[3]
|
||||
# fields: … local landing lang [canonical]
|
||||
lang = ""
|
||||
canon = name
|
||||
if len(parts) >= 8:
|
||||
tok = _norm_lang(parts[7])
|
||||
if tok:
|
||||
lang = tok
|
||||
if len(parts) >= 9:
|
||||
canon = parts[8]
|
||||
else:
|
||||
# legacy: field 8 = canonical
|
||||
canon = parts[7]
|
||||
if len(parts) >= 9:
|
||||
lang = _norm_lang(parts[8])
|
||||
if not lang:
|
||||
lang = "en"
|
||||
hosts = {name.lower(), bank.lower(), exchange.lower(), merchant.lower(), canon.lower()}
|
||||
# strip scheme if present
|
||||
hosts = {re.sub(r"^https?://", "", h).split("/")[0] for h in hosts}
|
||||
if any(h and h in hint for h in hosts):
|
||||
# prefer longer / more specific name match later — keep last match
|
||||
# that appears in conf order; FP aliases all share fr.
|
||||
best = lang
|
||||
if name.lower() in hint or canon.lower() in hint:
|
||||
return lang
|
||||
return best
|
||||
|
||||
|
||||
def ui_lang(explicit: str = "", host_hint: str = "") -> str:
|
||||
"""en (default) or fr.
|
||||
|
||||
- TALER_MON_LANG_SET=1 → honour TALER_MON_LANG / explicit only (no host auto).
|
||||
- Else: any *lefrancpaysan* / *francpaysan* host or log hint → fr
|
||||
(workstation env TALER_MON_LANG=en must not force English on FP domains).
|
||||
- Else: explicit / env / en.
|
||||
- TALER_MON_LANG_SET=1 → honour TALER_MON_LANG / explicit only.
|
||||
- Else TALER_DOMAIN_LANG env (set by load_domain_profile).
|
||||
- Else domains.conf `lang` for host_hint.
|
||||
- Else fallback *lefrancpaysan*/*francpaysan* → fr.
|
||||
- Else explicit / env / en.
|
||||
"""
|
||||
import os
|
||||
|
||||
env_lang = (os.environ.get("TALER_MON_LANG") or "").strip().lower()
|
||||
domain_lang = _norm_lang(os.environ.get("TALER_DOMAIN_LANG") or "")
|
||||
lang = (explicit or env_lang or "").strip().lower()
|
||||
locked = (os.environ.get("TALER_MON_LANG_SET") or "").strip() == "1"
|
||||
is_fp = bool(
|
||||
re.search(r"lefrancpaysan|francpaysan", host_hint or "", re.I)
|
||||
)
|
||||
|
||||
def _norm(v: str) -> str:
|
||||
if v in ("fr", "fra", "french"):
|
||||
return "fr"
|
||||
if v in ("en", "eng", "english"):
|
||||
return "en"
|
||||
return ""
|
||||
|
||||
if locked:
|
||||
return _norm(lang) or "en"
|
||||
if is_fp:
|
||||
return _norm_lang(lang) or "en"
|
||||
if domain_lang:
|
||||
return domain_lang
|
||||
conf_lang = domain_lang_from_conf(host_hint)
|
||||
if conf_lang:
|
||||
return conf_lang
|
||||
if re.search(r"lefrancpaysan|francpaysan", host_hint or "", re.I):
|
||||
return "fr"
|
||||
return _norm(lang) or "en"
|
||||
return _norm_lang(lang) or "en"
|
||||
|
||||
|
||||
def ui(lang: str, key: str, **kwargs) -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue