release 1.20.0: domains.conf locale l10n + optional German UI
Add locale column (fr-CH for FP, de-CH elsewhere; ch-FR/ch-DE aliases). Introduce UI lang=de (tags + sticky) without using de as any stock default.
This commit is contained in:
parent
915e361157
commit
c435df9728
8 changed files with 408 additions and 163 deletions
|
|
@ -203,9 +203,9 @@ Each monitored stack must say **what is bank, exchange, and merchant-backend**.
|
||||||
Edit **[domains.conf](./domains.conf)** (or set `TALER_DOMAINS_CONF=`):
|
Edit **[domains.conf](./domains.conf)** (or set `TALER_DOMAINS_CONF=`):
|
||||||
|
|
||||||
```text
|
```text
|
||||||
# name bank exchange merchant-backend currency local landing lang [canonical]
|
# name bank exchange merchant currency local landing lang locale [canonical]
|
||||||
taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 en
|
taler-ops.ch bank.… exchange.… my.… CHF 0 0 en de-CH
|
||||||
stage.lefrancpaysan.ch stage.bank.… stage.exchange.… stage.monnaie.… TESTPAYSAN 0 1 fr
|
stage.lefrancpaysan.ch stage.bank.… stage.exchange.… stage.monnaie.… TESTPAYSAN 0 1 fr fr-CH
|
||||||
```
|
```
|
||||||
|
|
||||||
| Field | Meaning |
|
| Field | Meaning |
|
||||||
|
|
@ -217,7 +217,8 @@ stage.lefrancpaysan.ch stage.bank.… stage.exchange.… stage.monnaie.… T
|
||||||
| **currency** | `GOA` / `KUDOS` / `CHF` / … |
|
| **currency** | `GOA` / `KUDOS` / `CHF` / … |
|
||||||
| **local** | `1` = koopa SSH stack; `0` = public only |
|
| **local** | `1` = koopa SSH stack; `0` = public only |
|
||||||
| **landing** | `1` = check `/intro` landings + assets; `0` = skip (TOPS / mytops) |
|
| **landing** | `1` = check `/intro` landings + assets; `0` = skip (TOPS / mytops) |
|
||||||
| **lang** | UI default **`en`** or **`fr`** when `TALER_MON_LANG_SET≠1` (source of truth; FP rows use **`fr`**) |
|
| **lang** | UI language **`en`** / **`fr`** / **`de`** when `TALER_MON_LANG_SET≠1`. Stock profiles use **en** or **fr** only — **`de` is never a default** (opt-in via `--lang de` or an explicit profile edit). |
|
||||||
|
| **locale** | Regional l10n (BCP 47): **`fr-CH`** for FrancPaysan (Suisse romande); **`de-CH`** for other Swiss stacks. Aliases `ch-FR` / `ch-DE` accepted. Not the same as UI `lang`. |
|
||||||
| **canonical** | optional label after alias (e.g. `my.taler-ops.ch` → `taler-ops.ch`) |
|
| **canonical** | optional label after alias (e.g. `my.taler-ops.ch` → `taler-ops.ch`) |
|
||||||
|
|
||||||
Workstation `TALER_MON_LANG=en` does **not** override a profile with `lang=fr`. Force English on FP only with `--lang en` / `TALER_MON_LANG_SET=1`.
|
Workstation `TALER_MON_LANG=en` does **not** override a profile with `lang=fr`. Force English on FP only with `--lang en` / `TALER_MON_LANG_SET=1`.
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.19.1
|
1.20.0
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre
|
||||||
|
|
||||||
| Tag | Date (UTC) | Notes |
|
| Tag | Date (UTC) | Notes |
|
||||||
|-----|------------|--------|
|
|-----|------------|--------|
|
||||||
|
| **v1.20.0** | 2026-07-19 | **Feature:** domains.conf **`locale`** (l10n) — FP **`fr-CH`**, others **`de-CH`** (aliases ch-FR/ch-DE); UI **`lang=de`** supported (sticky + console tags) but **never** a stock profile default; env `TALER_MON_LOCALE` / `TALER_DOMAIN_LOCALE`. |
|
||||||
| **v1.19.1** | 2026-07-19 | **Bugfix / docs:** DEPENDENCIES — e2e requires `taler-helper-sqlite3` on mon PATH + preflight; README domains.conf documents **`lang`** column. |
|
| **v1.19.1** | 2026-07-19 | **Bugfix / docs:** DEPENDENCIES — e2e requires `taler-helper-sqlite3` on mon PATH + preflight; README domains.conf documents **`lang`** column. |
|
||||||
| **v1.19.0** | 2026-07-19 | **Feature:** domains.conf **`lang`** column (en\|fr) is the global UI language default per stack; i18n + HTML read `TALER_DOMAIN_LANG` / conf (FP profiles `lang=fr`). |
|
| **v1.19.0** | 2026-07-19 | **Feature:** domains.conf **`lang`** column (en\|fr) is the global UI language default per stack; i18n + HTML read `TALER_DOMAIN_LANG` / conf (FP profiles `lang=fr`). |
|
||||||
| **v1.18.9** | 2026-07-19 | **Bugfix:** UI lang — *lefrancpaysan*/*francpaysan* always default **fr** unless `TALER_MON_LANG_SET=1` / `--lang`; workstation `TALER_MON_LANG=en` no longer locks English (host-agent + console_to_html). |
|
| **v1.18.9** | 2026-07-19 | **Bugfix:** UI lang — *lefrancpaysan*/*francpaysan* always default **fr** unless `TALER_MON_LANG_SET=1` / `--lang`; workstation `TALER_MON_LANG=en` no longer locks English (host-agent + console_to_html). |
|
||||||
|
|
|
||||||
69
domains.conf
69
domains.conf
|
|
@ -1,52 +1,53 @@
|
||||||
# taler-monitoring domain profiles
|
# taler-monitoring domain profiles
|
||||||
#
|
#
|
||||||
# When you add a stack, declare the three public endpoints here:
|
# When you add a stack, declare the three public endpoints here:
|
||||||
# name bank exchange merchant-backend currency local landing lang [canonical]
|
# name bank exchange merchant-backend currency local landing lang locale [canonical]
|
||||||
#
|
#
|
||||||
# - name: what -d / TALER_DOMAIN matches (aliases allowed as extra lines)
|
# - name: what -d / TALER_DOMAIN matches (aliases allowed as extra lines)
|
||||||
# - bank / exchange / merchant: hostname or full https:// URL
|
# - bank / exchange / merchant: hostname or full https:// URL
|
||||||
# - currency: GOA | KUDOS | CHF | … (empty or "-" = report only)
|
# - currency: GOA | KUDOS | CHF | … (empty or "-" = report only)
|
||||||
# - local: 1 = koopa SSH/inside/e2e stack; 0 = public-only
|
# - local: 1 = koopa SSH/inside/e2e stack; 0 = public-only
|
||||||
# - landing: 1 = check /intro landings + assets; 0 = skip (no GOA-style landings)
|
# - landing: 1 = check /intro landings + assets; 0 = skip (no GOA-style landings)
|
||||||
# - lang: UI language default for this profile (en|fr). Source of truth for i18n
|
# - lang: UI language for mon console/HTML (en|fr|de). Source of truth when
|
||||||
# when TALER_MON_LANG_SET≠1. Workstation env TALER_MON_LANG=en does not
|
# TALER_MON_LANG_SET≠1. Workstation TALER_MON_LANG=en does not override.
|
||||||
# override a profile that sets fr (e.g. *lefrancpaysan*).
|
# **de is supported but must not be used as a profile default** (no row
|
||||||
|
# sets lang=de unless an operator deliberately chooses it).
|
||||||
|
# - locale: BCP 47 regional locale for l10n defaults (not the same as UI lang).
|
||||||
|
# Use **fr-CH** (Suisse romande) for FrancPaysan; **de-CH** (Deutschschweiz)
|
||||||
|
# for other Swiss / default stacks. Accepts also ch-FR / ch-DE as aliases.
|
||||||
# - canonical: optional TALER_DOMAIN label after alias match
|
# - canonical: optional TALER_DOMAIN label after alias match
|
||||||
#
|
#
|
||||||
# Legacy lines without lang (old 8th field = canonical only) still parse: lang→en.
|
# Legacy lines without locale still parse (locale → de-CH except FP heuristic).
|
||||||
# CLI overrides: --lang / TALER_MON_LANG_SET=1
|
# CLI: --lang en|fr|de · TALER_MON_LANG_SET=1 locks UI lang
|
||||||
# Alternate file: TALER_DOMAINS_CONF=/path/to/domains.conf
|
# Alternate file: TALER_DOMAINS_CONF=/path/to/domains.conf
|
||||||
|
|
||||||
# Local GOA (koopa) — landings matter
|
# Local GOA (koopa) — landings matter · UI en · locale de-CH
|
||||||
koopa bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en hacktivism.ch
|
koopa bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en de-CH hacktivism.ch
|
||||||
hacktivism bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en hacktivism.ch
|
hacktivism bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en de-CH hacktivism.ch
|
||||||
hacktivism.ch bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en
|
hacktivism.ch bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 en de-CH
|
||||||
|
|
||||||
# Public demo (KUDOS) — has intro-style pages; keep soft landing checks
|
# Public demo (KUDOS)
|
||||||
taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 en demo.taler.net
|
taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 en de-CH demo.taler.net
|
||||||
demo.taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 en
|
demo.taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 en de-CH
|
||||||
|
|
||||||
# Public test stack (TESTKUDOS) — no GOA-style landings
|
# Public test stack (TESTKUDOS)
|
||||||
test.taler.net bank.test.taler.net exchange.test.taler.net backend.test.taler.net TESTKUDOS 0 0 en
|
test.taler.net bank.test.taler.net exchange.test.taler.net backend.test.taler.net TESTKUDOS 0 0 en de-CH
|
||||||
|
|
||||||
# TOPS CHF — multi-tenant merchant my.taler-ops.ch; no public GOA landings
|
# TOPS CHF
|
||||||
taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 en
|
taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 en de-CH
|
||||||
my.taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 en taler-ops.ch
|
my.taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 en de-CH taler-ops.ch
|
||||||
# Stage merchant FQDN is stage.my.taler-ops.ch (on betel); mon HTML /monitoring* stage-only
|
stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en de-CH
|
||||||
stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en
|
stage.my.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en de-CH stage.taler-ops.ch
|
||||||
stage.my.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en stage.taler-ops.ch
|
my.stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en de-CH stage.taler-ops.ch
|
||||||
my.stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch stage.my.taler-ops.ch CHF 0 0 en stage.taler-ops.ch
|
|
||||||
|
|
||||||
# Franc Paysan (Infomaniak) — merchant host is monnaie.* (not taler./backend.)
|
# Franc Paysan — UI fr · regional locale fr-CH (Suisse romande)
|
||||||
# UI default: French (lang=fr) for all FP prod hostnames
|
lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr fr-CH
|
||||||
lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr
|
monnaie.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr fr-CH lefrancpaysan.ch
|
||||||
monnaie.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr lefrancpaysan.ch
|
bank.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr fr-CH lefrancpaysan.ch
|
||||||
bank.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr lefrancpaysan.ch
|
exchange.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr fr-CH lefrancpaysan.ch
|
||||||
exchange.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 fr lefrancpaysan.ch
|
|
||||||
|
|
||||||
# Stage TESTPAYSAN — landings on / + farmer shops under stage.monnaie…/shops/
|
# Stage TESTPAYSAN — UI fr · locale fr-CH
|
||||||
# UI default: French (lang=fr)
|
stage.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr fr-CH
|
||||||
stage.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr
|
stage.bank.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr fr-CH stage.lefrancpaysan.ch
|
||||||
stage.bank.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr stage.lefrancpaysan.ch
|
stage.exchange.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr fr-CH stage.lefrancpaysan.ch
|
||||||
stage.exchange.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr stage.lefrancpaysan.ch
|
stage.monnaie.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr fr-CH stage.lefrancpaysan.ch
|
||||||
stage.monnaie.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 fr stage.lefrancpaysan.ch
|
|
||||||
|
|
|
||||||
233
i18n.sh
233
i18n.sh
|
|
@ -1,19 +1,24 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# i18n.sh — language for taler-monitoring console + HTML chrome
|
# i18n.sh — UI language + regional locale for taler-monitoring console + HTML
|
||||||
#
|
#
|
||||||
# TALER_MON_LANG=en|fr
|
# UI language (mon badges / sticky chrome):
|
||||||
# TALER_MON_LANG_SET=1 → language is explicit (--lang only); do not override.
|
# TALER_MON_LANG=en|fr|de
|
||||||
# Auto (SET≠1), in order:
|
# TALER_MON_LANG_SET=1 → explicit (--lang); do not override.
|
||||||
# 1) TALER_DOMAIN_LANG from domains.conf profile (preferred — source of truth)
|
# Auto (SET≠1): TALER_DOMAIN_LANG from domains.conf `lang` column.
|
||||||
# 2) fallback hostname heuristic *lefrancpaysan*/*francpaysan* → fr
|
# de is supported but never a stock profile default (no domains.conf row uses lang=de).
|
||||||
# 3) else keep workstation env TALER_MON_LANG or en
|
|
||||||
#
|
#
|
||||||
# domains.conf column `lang` (see suite domains.conf) is the global definition.
|
# Regional locale (l10n defaults, BCP 47 — not the same as UI lang):
|
||||||
# Bare TALER_MON_LANG=en in ~/.config must not override a profile lang=fr.
|
# TALER_MON_LOCALE / TALER_DOMAIN_LOCALE e.g. fr-CH, de-CH
|
||||||
|
# From domains.conf `locale` column (fr-CH for FP, de-CH for others).
|
||||||
|
# Aliases ch-FR / ch-DE accepted and normalized to fr-CH / de-CH.
|
||||||
|
#
|
||||||
|
# domains.conf is the source of truth for both lang and locale.
|
||||||
|
|
||||||
: "${TALER_MON_LANG:=}"
|
: "${TALER_MON_LANG:=}"
|
||||||
: "${TALER_MON_LANG_SET:=0}"
|
: "${TALER_MON_LANG_SET:=0}"
|
||||||
: "${TALER_DOMAIN_LANG:=}"
|
: "${TALER_DOMAIN_LANG:=}"
|
||||||
|
: "${TALER_DOMAIN_LOCALE:=}"
|
||||||
|
: "${TALER_MON_LOCALE:=}"
|
||||||
|
|
||||||
i18n_init() {
|
i18n_init() {
|
||||||
# Only TALER_MON_LANG_SET=1 is "explicit". Do not promote non-empty TALER_MON_LANG
|
# Only TALER_MON_LANG_SET=1 is "explicit". Do not promote non-empty TALER_MON_LANG
|
||||||
|
|
@ -24,7 +29,6 @@ i18n_init() {
|
||||||
else
|
else
|
||||||
case "${TALER_DOMAIN:-}" in
|
case "${TALER_DOMAIN:-}" in
|
||||||
*lefrancpaysan*|*francpaysan*)
|
*lefrancpaysan*|*francpaysan*)
|
||||||
# fallback if domain not (yet) in domains.conf
|
|
||||||
TALER_MON_LANG=fr
|
TALER_MON_LANG=fr
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|
@ -37,89 +41,162 @@ i18n_init() {
|
||||||
fi
|
fi
|
||||||
case "${TALER_MON_LANG}" in
|
case "${TALER_MON_LANG}" in
|
||||||
fr|FR|fra|french) TALER_MON_LANG=fr ;;
|
fr|FR|fra|french) TALER_MON_LANG=fr ;;
|
||||||
|
de|DE|deu|ger|german|deutsch) TALER_MON_LANG=de ;;
|
||||||
*) TALER_MON_LANG=en ;;
|
*) TALER_MON_LANG=en ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Regional locale from profile (or FP/other fallback)
|
||||||
|
if [ -n "${TALER_DOMAIN_LOCALE:-}" ]; then
|
||||||
|
TALER_MON_LOCALE="$TALER_DOMAIN_LOCALE"
|
||||||
|
elif [ -z "${TALER_MON_LOCALE:-}" ]; then
|
||||||
|
case "${TALER_DOMAIN:-}" in
|
||||||
|
*lefrancpaysan*|*francpaysan*) TALER_MON_LOCALE=fr-CH ;;
|
||||||
|
*) TALER_MON_LOCALE=de-CH ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
# normalize aliases
|
||||||
|
case "$(printf '%s' "$TALER_MON_LOCALE" | tr '[:upper:]' '[:lower:]' | tr '_' '-')" in
|
||||||
|
fr-ch|ch-fr) TALER_MON_LOCALE=fr-CH ;;
|
||||||
|
de-ch|ch-de) TALER_MON_LOCALE=de-CH ;;
|
||||||
|
en-ch|ch-en) TALER_MON_LOCALE=en-CH ;;
|
||||||
|
esac
|
||||||
|
|
||||||
export TALER_MON_LANG
|
export TALER_MON_LANG
|
||||||
export TALER_MON_LANG_SET
|
export TALER_MON_LANG_SET
|
||||||
export TALER_DOMAIN_LANG
|
export TALER_DOMAIN_LANG
|
||||||
|
export TALER_DOMAIN_LOCALE
|
||||||
|
export TALER_MON_LOCALE
|
||||||
}
|
}
|
||||||
|
|
||||||
i18n_tag() {
|
i18n_tag() {
|
||||||
local t="$1"
|
local t="$1"
|
||||||
if [ "${TALER_MON_LANG:-en}" != "fr" ]; then
|
case "${TALER_MON_LANG:-en}" in
|
||||||
printf '%s' "$t"
|
fr)
|
||||||
return 0
|
case "$t" in
|
||||||
fi
|
OK) printf 'OK' ;;
|
||||||
case "$t" in
|
ERROR) printf 'ERREUR' ;;
|
||||||
OK) printf 'OK' ;;
|
WARN) printf 'AVERT' ;;
|
||||||
ERROR) printf 'ERREUR' ;;
|
INFO) printf 'INFO' ;;
|
||||||
WARN) printf 'AVERT' ;;
|
BLOCKER) printf 'BLOCAGE' ;;
|
||||||
INFO) printf 'INFO' ;;
|
BLOCK) printf 'BLOC' ;;
|
||||||
BLOCKER) printf 'BLOCAGE' ;;
|
SUMMARY) printf 'RESUME' ;;
|
||||||
BLOCK) printf 'BLOC' ;;
|
PROG|PROGRESS) printf 'PROG' ;;
|
||||||
SUMMARY) printf 'RESUME' ;;
|
*) printf '%s' "$t" ;;
|
||||||
PROG|PROGRESS) printf 'PROG' ;;
|
esac
|
||||||
*) printf '%s' "$t" ;;
|
;;
|
||||||
|
de)
|
||||||
|
case "$t" in
|
||||||
|
OK) printf 'OK' ;;
|
||||||
|
ERROR) printf 'FEHLER' ;;
|
||||||
|
WARN) printf 'WARNUNG' ;;
|
||||||
|
INFO) printf 'INFO' ;;
|
||||||
|
BLOCKER) printf 'BLOCKER' ;;
|
||||||
|
BLOCK) printf 'BLOCK' ;;
|
||||||
|
SUMMARY) printf 'ZUSAMMENFASSUNG' ;;
|
||||||
|
PROG|PROGRESS) printf 'PROG' ;;
|
||||||
|
*) printf '%s' "$t" ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' "$t"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
i18n_text() {
|
i18n_text() {
|
||||||
local s="$*"
|
local s="$*"
|
||||||
if [ "${TALER_MON_LANG:-en}" != "fr" ] || [ -z "$s" ]; then
|
[ -z "$s" ] && { printf '%s' "$s"; return 0; }
|
||||||
printf '%s' "$s"
|
case "${TALER_MON_LANG:-en}" in
|
||||||
return 0
|
fr)
|
||||||
fi
|
case "$s" in
|
||||||
case "$s" in
|
"numbered checks this run:") printf 'controles numerotes de cette execution :' ;;
|
||||||
"numbered checks this run:") printf 'controles numerotes de cette execution :' ;;
|
"numbered checks:") printf 'controles numerotes :' ;;
|
||||||
"numbered checks:") printf 'controles numerotes :' ;;
|
"(global done/total)") printf '(fait/total global)' ;;
|
||||||
"(global done/total)") printf '(fait/total global)' ;;
|
"global checks:") printf 'controles globaux :' ;;
|
||||||
"global checks:") printf 'controles globaux :' ;;
|
"failed — see list above"|"failed - see list above") printf 'echec — voir la liste ci-dessus' ;;
|
||||||
"failed — see list above"|"failed - see list above") printf 'echec — voir la liste ci-dessus' ;;
|
"BLOCKERS · pay/withdraw cannot finish") printf 'BLOCAGES · paiement/retrait impossible' ;;
|
||||||
"BLOCKERS · pay/withdraw cannot finish") printf 'BLOCAGES · paiement/retrait impossible' ;;
|
"BLOCKERS (pay/withdraw cannot finish)") printf 'BLOCAGES (paiement/retrait impossible)' ;;
|
||||||
"BLOCKERS (pay/withdraw cannot finish)") printf 'BLOCAGES (paiement/retrait impossible)' ;;
|
"ERRORS · failed checks") printf 'ERREURS · controles en echec' ;;
|
||||||
"ERRORS · failed checks") printf 'ERREURS · controles en echec' ;;
|
"ERRORS (failed checks)") printf 'ERREURS (controles en echec)' ;;
|
||||||
"ERRORS (failed checks)") printf 'ERREURS (controles en echec)' ;;
|
"pay/withdraw cannot finish") printf 'paiement/retrait impossible a terminer' ;;
|
||||||
"pay/withdraw cannot finish") printf 'paiement/retrait impossible a terminer' ;;
|
"SUMMARY") printf 'RESUME' ;;
|
||||||
"SUMMARY") printf 'RESUME' ;;
|
"totals:") printf 'totaux :' ;;
|
||||||
"totals:") printf 'totaux :' ;;
|
"all clear") printf 'tout est clair' ;;
|
||||||
"all clear") printf 'tout est clair' ;;
|
"warnings only (no hard fail)") printf 'avertissements seulement (pas d'\''echec dur)' ;;
|
||||||
"warnings only (no hard fail)") printf 'avertissements seulement (pas d'\''echec dur)' ;;
|
"monitoring") printf 'surveillance' ;;
|
||||||
"monitoring") printf 'surveillance' ;;
|
"surface") printf 'surface' ;;
|
||||||
"surface") printf 'surface' ;;
|
"aptdeploy") printf 'aptdeploy' ;;
|
||||||
"aptdeploy") printf 'aptdeploy' ;;
|
"container") printf 'conteneur' ;;
|
||||||
"container") printf 'conteneur' ;;
|
"disk") printf 'disque' ;;
|
||||||
"disk") printf 'disque' ;;
|
"package") printf 'paquet' ;;
|
||||||
"package") printf 'paquet' ;;
|
"version") printf 'version' ;;
|
||||||
"version") printf 'version' ;;
|
"reachability") printf 'accessibilite' ;;
|
||||||
"reachability") printf 'accessibilite' ;;
|
"server-header") printf 'en-tete Server' ;;
|
||||||
"server-header") printf 'en-tete Server' ;;
|
"inventory") printf 'inventaire' ;;
|
||||||
"inventory") printf 'inventaire' ;;
|
"flags") printf 'options' ;;
|
||||||
"flags") printf 'options' ;;
|
"target domain") printf 'domaine cible' ;;
|
||||||
"target domain") printf 'domaine cible' ;;
|
"currency") printf 'devise' ;;
|
||||||
"currency") printf 'devise' ;;
|
"phases") printf 'phases' ;;
|
||||||
"phases") printf 'phases' ;;
|
"access") printf 'acces' ;;
|
||||||
"access") printf 'acces' ;;
|
*)
|
||||||
|
local out="$s"
|
||||||
|
out=${out//shared library missing/bibliotheque partagee manquante}
|
||||||
|
out=${out//not active/non actif}
|
||||||
|
out=${out//does not resolve/ne resout pas}
|
||||||
|
out=${out//from Server header/depuis en-tete Server}
|
||||||
|
out=${out//public HTTPS/HTTPS public}
|
||||||
|
out=${out//no SSH/sans SSH}
|
||||||
|
out=${out//failed — see list above/echec — voir la liste ci-dessus}
|
||||||
|
printf '%s' "$out"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
de)
|
||||||
|
case "$s" in
|
||||||
|
"numbered checks this run:") printf 'Nummerierte Pruefungen dieser Ausfuehrung :' ;;
|
||||||
|
"numbered checks:") printf 'Nummerierte Pruefungen :' ;;
|
||||||
|
"(global done/total)") printf '(fertig/gesamt global)' ;;
|
||||||
|
"global checks:") printf 'Globale Pruefungen :' ;;
|
||||||
|
"failed — see list above"|"failed - see list above") printf 'fehlgeschlagen — siehe Liste oben' ;;
|
||||||
|
"BLOCKERS · pay/withdraw cannot finish") printf 'BLOCKER · Zahlung/Abhebung nicht moeglich' ;;
|
||||||
|
"BLOCKERS (pay/withdraw cannot finish)") printf 'BLOCKER (Zahlung/Abhebung nicht moeglich)' ;;
|
||||||
|
"ERRORS · failed checks") printf 'FEHLER · fehlgeschlagene Pruefungen' ;;
|
||||||
|
"ERRORS (failed checks)") printf 'FEHLER (fehlgeschlagene Pruefungen)' ;;
|
||||||
|
"pay/withdraw cannot finish") printf 'Zahlung/Abhebung kann nicht beendet werden' ;;
|
||||||
|
"SUMMARY") printf 'ZUSAMMENFASSUNG' ;;
|
||||||
|
"totals:") printf 'Summen :' ;;
|
||||||
|
"all clear") printf 'alles in Ordnung' ;;
|
||||||
|
"warnings only (no hard fail)") printf 'nur Warnungen (kein harter Fehler)' ;;
|
||||||
|
"monitoring") printf 'Ueberwachung' ;;
|
||||||
|
"surface") printf 'Surface' ;;
|
||||||
|
"aptdeploy") printf 'aptdeploy' ;;
|
||||||
|
"container") printf 'Container' ;;
|
||||||
|
"disk") printf 'Disk' ;;
|
||||||
|
"package") printf 'Paket' ;;
|
||||||
|
"version") printf 'Version' ;;
|
||||||
|
"reachability") printf 'Erreichbarkeit' ;;
|
||||||
|
"server-header") printf 'Server-Header' ;;
|
||||||
|
"inventory") printf 'Inventar' ;;
|
||||||
|
"flags") printf 'Flags' ;;
|
||||||
|
"target domain") printf 'Zieldomaene' ;;
|
||||||
|
"currency") printf 'Waehrung' ;;
|
||||||
|
"phases") printf 'Phasen' ;;
|
||||||
|
"access") printf 'Zugang' ;;
|
||||||
|
*)
|
||||||
|
local outd="$s"
|
||||||
|
outd=${outd//shared library missing/gemeinsame Bibliothek fehlt}
|
||||||
|
outd=${outd//not active/nicht aktiv}
|
||||||
|
outd=${outd//does not resolve/loest nicht auf}
|
||||||
|
outd=${outd//from Server header/aus Server-Header}
|
||||||
|
outd=${outd//public HTTPS/oeffentliches HTTPS}
|
||||||
|
outd=${outd//no SSH/ohne SSH}
|
||||||
|
outd=${outd//failed — see list above/fehlgeschlagen — siehe Liste oben}
|
||||||
|
printf '%s' "$outd"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
local out="$s"
|
printf '%s' "$s"
|
||||||
out=${out//shared library missing/bibliotheque partagee manquante}
|
|
||||||
out=${out//shared library error/erreur de bibliotheque partagee}
|
|
||||||
out=${out//not active/non actif}
|
|
||||||
out=${out//after_start/apres_demarrage}
|
|
||||||
out=${out//catalogued but not reachable/catalogue mais inaccessible}
|
|
||||||
out=${out//does not resolve/ne resout pas}
|
|
||||||
out=${out//protocol confirmed/protocole confirme}
|
|
||||||
out=${out//catalogued service OK/service catalogue OK}
|
|
||||||
out=${out//from Server header/depuis en-tete Server}
|
|
||||||
out=${out//OSV clean/OSV sans vulnerabilite}
|
|
||||||
out=${out//actionable vuln/vuln. actionnable}
|
|
||||||
out=${out//header version · not Debian pkg/version en-tete · pas paquet Debian}
|
|
||||||
out=${out//RUN_TIMEOUT exceeded/RUN_TIMEOUT depasse}
|
|
||||||
out=${out//public HTTPS/HTTPS public}
|
|
||||||
out=${out//container status/etat du conteneur}
|
|
||||||
out=${out//remote-only/uniquement distant}
|
|
||||||
out=${out//no SSH/sans SSH}
|
|
||||||
out=${out//failed — see list above/echec — voir la liste ci-dessus}
|
|
||||||
printf '%s' "$out"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
lib.sh
70
lib.sh
|
|
@ -166,24 +166,53 @@ set_taler_stack() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Normalize domains.conf lang token → en|fr (empty if not a lang token).
|
# Normalize domains.conf UI lang token → en|fr|de (empty if not a lang token).
|
||||||
|
# Note: de is valid for --lang / explicit profile, but no stock profile defaults to de.
|
||||||
_domain_lang_token() {
|
_domain_lang_token() {
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
en|EN|eng|english) printf 'en' ;;
|
en|EN|eng|english) printf 'en' ;;
|
||||||
fr|FR|fra|french) printf 'fr' ;;
|
fr|FR|fra|french) printf 'fr' ;;
|
||||||
|
de|DE|deu|ger|german|deutsch) printf 'de' ;;
|
||||||
*) printf '' ;;
|
*) printf '' ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Normalize regional locale → BCP 47 (fr-CH, de-CH, en-CH, …). Empty if unknown.
|
||||||
|
# Accepts fr-CH, fr_CH, ch-FR / de-CH, ch-DE (user-friendly aliases).
|
||||||
|
_domain_locale_token() {
|
||||||
|
local t="${1:-}"
|
||||||
|
t=$(printf '%s' "$t" | tr '[:upper:]' '[:lower:]' | tr '_' '-')
|
||||||
|
case "$t" in
|
||||||
|
fr-ch|ch-fr|fr_ch) printf 'fr-CH' ;;
|
||||||
|
de-ch|ch-de|de_ch) printf 'de-CH' ;;
|
||||||
|
en-ch|ch-en|en_ch) printf 'en-CH' ;;
|
||||||
|
en-us|en-gb|fr-fr|de-de|it-ch|rm-ch)
|
||||||
|
# pass through other xx-YY
|
||||||
|
printf '%s' "$t" | awk -F- '{printf "%s-%s", tolower($1), toupper($2)}'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# bare xx-YY pattern
|
||||||
|
if printf '%s' "$t" | grep -qE '^[a-z]{2}-[a-z]{2}$'; then
|
||||||
|
printf '%s' "$t" | awk -F- '{printf "%s-%s", tolower($1), toupper($2)}'
|
||||||
|
else
|
||||||
|
printf ''
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
# Load first matching profile from domains.conf.
|
# Load first matching profile from domains.conf.
|
||||||
# Fields (whitespace-separated; # comments; blank lines ignored):
|
# Fields (whitespace-separated; # comments; blank lines ignored):
|
||||||
# name bank exchange merchant currency local[0|1] landing[0|1] lang[en|fr] [canonical]
|
# name bank exchange merchant currency local landing lang locale [canonical]
|
||||||
# Legacy: 8th field may be canonical only (no lang) — lang defaults to en.
|
# Legacy:
|
||||||
# Sets TALER_DOMAIN_LANG from the profile (i18n source of truth when SET≠1).
|
# … landing lang [canonical] → locale defaulted
|
||||||
|
# … landing [canonical] → lang=en, locale defaulted
|
||||||
|
# Sets TALER_DOMAIN_LANG + TALER_DOMAIN_LOCALE from the profile.
|
||||||
# Returns 0 if found, 1 if not.
|
# Returns 0 if found, 1 if not.
|
||||||
load_domain_profile() {
|
load_domain_profile() {
|
||||||
local want="$1" conf="${TALER_DOMAINS_CONF:-}"
|
local want="$1" conf="${TALER_DOMAINS_CONF:-}"
|
||||||
local line name bank exchange merchant currency local_stack landing canon profile_lang f8 f9
|
local line name bank exchange merchant currency local_stack landing canon
|
||||||
|
local profile_lang profile_locale f8 f9 f10
|
||||||
[ -n "$want" ] || return 1
|
[ -n "$want" ] || return 1
|
||||||
[ -n "$conf" ] && [ -f "$conf" ] || return 1
|
[ -n "$conf" ] && [ -f "$conf" ] || return 1
|
||||||
|
|
||||||
|
|
@ -202,28 +231,53 @@ load_domain_profile() {
|
||||||
landing="${7:-}"
|
landing="${7:-}"
|
||||||
f8="${8:-}"
|
f8="${8:-}"
|
||||||
f9="${9:-}"
|
f9="${9:-}"
|
||||||
|
f10="${10:-}"
|
||||||
canon="$name"
|
canon="$name"
|
||||||
profile_lang=""
|
profile_lang=""
|
||||||
|
profile_locale=""
|
||||||
# Backward compat: old 7th field was canonical domain (contains a dot)
|
# Backward compat: old 7th field was canonical domain (contains a dot)
|
||||||
if [ -n "$landing" ] && [[ "$landing" == *.* && "$landing" != "0" && "$landing" != "1" ]]; then
|
if [ -n "$landing" ] && [[ "$landing" == *.* && "$landing" != "0" && "$landing" != "1" ]]; then
|
||||||
canon="$landing"
|
canon="$landing"
|
||||||
landing=""
|
landing=""
|
||||||
f8="${7:-}"
|
f8="${7:-}"
|
||||||
f9="${8:-}"
|
f9="${8:-}"
|
||||||
|
f10="${9:-}"
|
||||||
fi
|
fi
|
||||||
if [ -n "$f8" ]; then
|
if [ -n "$f8" ]; then
|
||||||
profile_lang=$(_domain_lang_token "$f8")
|
profile_lang=$(_domain_lang_token "$f8")
|
||||||
if [ -n "$profile_lang" ]; then
|
if [ -n "$profile_lang" ]; then
|
||||||
canon="${f9:-$name}"
|
# modern: lang [locale] [canonical]
|
||||||
|
profile_locale=$(_domain_locale_token "$f9")
|
||||||
|
if [ -n "$profile_locale" ]; then
|
||||||
|
canon="${f10:-$name}"
|
||||||
|
else
|
||||||
|
# lang + canonical (no locale column)
|
||||||
|
if [ -n "$f9" ] && [ -z "$(_domain_lang_token "$f9")" ]; then
|
||||||
|
canon="$f9"
|
||||||
|
else
|
||||||
|
canon="${f9:-$name}"
|
||||||
|
fi
|
||||||
|
profile_locale=$(_domain_locale_token "$f10")
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# legacy: field 8 = canonical, optional field 9 = lang
|
# legacy: field 8 = canonical only
|
||||||
canon="$f8"
|
canon="$f8"
|
||||||
profile_lang=$(_domain_lang_token "$f9")
|
profile_lang=$(_domain_lang_token "$f9")
|
||||||
|
profile_locale=$(_domain_locale_token "${f10:-$f9}")
|
||||||
|
[ -z "$profile_lang" ] && profile_lang=en
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
[ -z "$profile_lang" ] && profile_lang=en
|
[ -z "$profile_lang" ] && profile_lang=en
|
||||||
|
if [ -z "$profile_locale" ]; then
|
||||||
|
# default regional locale: FP → fr-CH, else de-CH
|
||||||
|
case "$name$canon$bank$merchant" in
|
||||||
|
*lefrancpaysan*|*francpaysan*) profile_locale=fr-CH ;;
|
||||||
|
*) profile_locale=de-CH ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
TALER_DOMAIN_LANG="$profile_lang"
|
TALER_DOMAIN_LANG="$profile_lang"
|
||||||
export TALER_DOMAIN_LANG
|
TALER_DOMAIN_LOCALE="$profile_locale"
|
||||||
|
export TALER_DOMAIN_LANG TALER_DOMAIN_LOCALE
|
||||||
set_taler_stack "$bank" "$exchange" "$merchant" "$currency" "$local_stack" "$landing" "$canon"
|
set_taler_stack "$bank" "$exchange" "$merchant" "$currency" "$local_stack" "$landing" "$canon"
|
||||||
return 0
|
return 0
|
||||||
done <"$conf"
|
done <"$conf"
|
||||||
|
|
|
||||||
|
|
@ -49,44 +49,61 @@ def _norm_lang(v: str) -> str:
|
||||||
v = (v or "").strip().lower()
|
v = (v or "").strip().lower()
|
||||||
if v in ("fr", "fra", "french"):
|
if v in ("fr", "fra", "french"):
|
||||||
return "fr"
|
return "fr"
|
||||||
|
if v in ("de", "deu", "ger", "german", "deutsch"):
|
||||||
|
return "de"
|
||||||
if v in ("en", "eng", "english"):
|
if v in ("en", "eng", "english"):
|
||||||
return "en"
|
return "en"
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def domain_lang_from_conf(host_hint: str = "") -> str:
|
def _norm_locale(v: str) -> str:
|
||||||
"""Look up UI lang from domains.conf (suite profile `lang` column).
|
"""BCP 47 regional locale; aliases ch-FR/ch-DE → fr-CH/de-CH."""
|
||||||
|
t = (v or "").strip().lower().replace("_", "-")
|
||||||
|
aliases = {
|
||||||
|
"fr-ch": "fr-CH",
|
||||||
|
"ch-fr": "fr-CH",
|
||||||
|
"de-ch": "de-CH",
|
||||||
|
"ch-de": "de-CH",
|
||||||
|
"en-ch": "en-CH",
|
||||||
|
"ch-en": "en-CH",
|
||||||
|
}
|
||||||
|
if t in aliases:
|
||||||
|
return aliases[t]
|
||||||
|
m = re.fullmatch(r"([a-z]{2})-([a-z]{2})", t)
|
||||||
|
if m:
|
||||||
|
return f"{m.group(1)}-{m.group(2).upper()}"
|
||||||
|
return ""
|
||||||
|
|
||||||
Matches host_hint against profile name, bank, exchange, merchant, or
|
|
||||||
canonical fields. Returns '' if no profile matches.
|
def _domains_conf_path() -> "object | None":
|
||||||
"""
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
hint = (host_hint or "").lower()
|
|
||||||
if not hint.strip():
|
|
||||||
return ""
|
|
||||||
|
|
||||||
conf = os.environ.get("TALER_DOMAINS_CONF") or ""
|
conf = os.environ.get("TALER_DOMAINS_CONF") or ""
|
||||||
candidates = []
|
candidates = []
|
||||||
if conf:
|
if conf:
|
||||||
candidates.append(Path(conf))
|
candidates.append(Path(conf))
|
||||||
# suite root next to site-gen/
|
|
||||||
here = Path(__file__).resolve().parent
|
here = Path(__file__).resolve().parent
|
||||||
candidates.append(here.parent / "domains.conf")
|
candidates.append(here.parent / "domains.conf")
|
||||||
# cwd / mon root
|
|
||||||
candidates.append(Path("domains.conf"))
|
candidates.append(Path("domains.conf"))
|
||||||
|
return next((p for p in candidates if p.is_file()), None)
|
||||||
|
|
||||||
path = next((p for p in candidates if p.is_file()), None)
|
|
||||||
|
def domain_profile_from_conf(host_hint: str = "") -> tuple[str, str]:
|
||||||
|
"""Return (lang, locale) from domains.conf for host_hint; ('','') if none."""
|
||||||
|
hint = (host_hint or "").lower()
|
||||||
|
if not hint.strip():
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
path = _domains_conf_path()
|
||||||
if path is None:
|
if path is None:
|
||||||
return ""
|
return "", ""
|
||||||
|
|
||||||
best = ""
|
|
||||||
try:
|
try:
|
||||||
text = path.read_text(encoding="utf-8", errors="replace")
|
text = path.read_text(encoding="utf-8", errors="replace")
|
||||||
except OSError:
|
except OSError:
|
||||||
return ""
|
return "", ""
|
||||||
|
|
||||||
|
best_lang, best_loc = "", ""
|
||||||
for raw in text.splitlines():
|
for raw in text.splitlines():
|
||||||
line = raw.split("#", 1)[0].strip()
|
line = raw.split("#", 1)[0].strip()
|
||||||
if not line:
|
if not line:
|
||||||
|
|
@ -95,41 +112,62 @@ def domain_lang_from_conf(host_hint: str = "") -> str:
|
||||||
if len(parts) < 5:
|
if len(parts) < 5:
|
||||||
continue
|
continue
|
||||||
name, bank, exchange, merchant = parts[0], parts[1], parts[2], parts[3]
|
name, bank, exchange, merchant = parts[0], parts[1], parts[2], parts[3]
|
||||||
# fields: … local landing lang [canonical]
|
lang, locale, canon = "", "", name
|
||||||
lang = ""
|
|
||||||
canon = name
|
|
||||||
if len(parts) >= 8:
|
if len(parts) >= 8:
|
||||||
tok = _norm_lang(parts[7])
|
tok = _norm_lang(parts[7])
|
||||||
if tok:
|
if tok:
|
||||||
lang = tok
|
lang = tok
|
||||||
if len(parts) >= 9:
|
if len(parts) >= 9:
|
||||||
canon = parts[8]
|
loc = _norm_locale(parts[8])
|
||||||
|
if loc:
|
||||||
|
locale = loc
|
||||||
|
if len(parts) >= 10:
|
||||||
|
canon = parts[9]
|
||||||
|
else:
|
||||||
|
# lang + canonical (no locale)
|
||||||
|
canon = parts[8]
|
||||||
|
if len(parts) >= 10:
|
||||||
|
locale = _norm_locale(parts[9])
|
||||||
else:
|
else:
|
||||||
# legacy: field 8 = canonical
|
|
||||||
canon = parts[7]
|
canon = parts[7]
|
||||||
if len(parts) >= 9:
|
if len(parts) >= 9:
|
||||||
lang = _norm_lang(parts[8])
|
lang = _norm_lang(parts[8])
|
||||||
|
if len(parts) >= 10:
|
||||||
|
locale = _norm_locale(parts[9])
|
||||||
|
elif len(parts) >= 9:
|
||||||
|
locale = _norm_locale(parts[8])
|
||||||
if not lang:
|
if not lang:
|
||||||
lang = "en"
|
lang = "en"
|
||||||
|
if not locale:
|
||||||
|
blob = f"{name}{canon}{bank}{merchant}".lower()
|
||||||
|
locale = "fr-CH" if ("lefrancpaysan" in blob or "francpaysan" in blob) else "de-CH"
|
||||||
hosts = {name.lower(), bank.lower(), exchange.lower(), merchant.lower(), canon.lower()}
|
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}
|
hosts = {re.sub(r"^https?://", "", h).split("/")[0] for h in hosts}
|
||||||
if any(h and h in hint 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
|
best_lang, best_loc = lang, locale
|
||||||
# that appears in conf order; FP aliases all share fr.
|
|
||||||
best = lang
|
|
||||||
if name.lower() in hint or canon.lower() in hint:
|
if name.lower() in hint or canon.lower() in hint:
|
||||||
return lang
|
return lang, locale
|
||||||
return best
|
return best_lang, best_loc
|
||||||
|
|
||||||
|
|
||||||
|
def domain_lang_from_conf(host_hint: str = "") -> str:
|
||||||
|
"""Look up UI lang from domains.conf (suite profile `lang` column)."""
|
||||||
|
lang, _ = domain_profile_from_conf(host_hint)
|
||||||
|
return lang
|
||||||
|
|
||||||
|
|
||||||
|
def domain_locale_from_conf(host_hint: str = "") -> str:
|
||||||
|
"""Look up regional locale from domains.conf (`locale` column)."""
|
||||||
|
_, loc = domain_profile_from_conf(host_hint)
|
||||||
|
return loc
|
||||||
|
|
||||||
|
|
||||||
def ui_lang(explicit: str = "", host_hint: str = "") -> str:
|
def ui_lang(explicit: str = "", host_hint: str = "") -> str:
|
||||||
"""en (default) or fr.
|
"""en | fr | de (de never a stock profile default).
|
||||||
|
|
||||||
- TALER_MON_LANG_SET=1 → honour TALER_MON_LANG / explicit only.
|
- TALER_MON_LANG_SET=1 → honour TALER_MON_LANG / explicit only.
|
||||||
- Else TALER_DOMAIN_LANG env (set by load_domain_profile).
|
- Else TALER_DOMAIN_LANG / domains.conf `lang`.
|
||||||
- Else domains.conf `lang` for host_hint.
|
- Else fallback *lefrancpaysan* → fr.
|
||||||
- Else fallback *lefrancpaysan*/*francpaysan* → fr.
|
|
||||||
- Else explicit / env / en.
|
- Else explicit / env / en.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
@ -151,8 +189,24 @@ def ui_lang(explicit: str = "", host_hint: str = "") -> str:
|
||||||
return _norm_lang(lang) or "en"
|
return _norm_lang(lang) or "en"
|
||||||
|
|
||||||
|
|
||||||
|
def ui_locale(host_hint: str = "") -> str:
|
||||||
|
"""Regional locale fr-CH / de-CH from env or domains.conf."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
for key in ("TALER_MON_LOCALE", "TALER_DOMAIN_LOCALE"):
|
||||||
|
loc = _norm_locale(os.environ.get(key) or "")
|
||||||
|
if loc:
|
||||||
|
return loc
|
||||||
|
conf = domain_locale_from_conf(host_hint)
|
||||||
|
if conf:
|
||||||
|
return conf
|
||||||
|
if re.search(r"lefrancpaysan|francpaysan", host_hint or "", re.I):
|
||||||
|
return "fr-CH"
|
||||||
|
return "de-CH"
|
||||||
|
|
||||||
|
|
||||||
def ui(lang: str, key: str, **kwargs) -> str:
|
def ui(lang: str, key: str, **kwargs) -> str:
|
||||||
"""UI chrome strings for sticky bar (English default; French for FrancPaysan)."""
|
"""UI chrome strings (en default; fr for FP; de available via --lang de, never stock default)."""
|
||||||
en = {
|
en = {
|
||||||
"errors": "ERRORS",
|
"errors": "ERRORS",
|
||||||
"warnings": "WARNINGS",
|
"warnings": "WARNINGS",
|
||||||
|
|
@ -373,7 +427,60 @@ def ui(lang: str, key: str, **kwargs) -> str:
|
||||||
"ago_d": "il y a {n} j",
|
"ago_d": "il y a {n} j",
|
||||||
"age_title": "âge de la page · mise à jour chaque seconde",
|
"age_title": "âge de la page · mise à jour chaque seconde",
|
||||||
}
|
}
|
||||||
table = fr if lang == "fr" else en
|
# German sticky chrome only (full pack falls back to en for missing keys).
|
||||||
|
# Not used as any domains.conf default — operators may pass --lang de.
|
||||||
|
de = {
|
||||||
|
"errors": "FEHLER",
|
||||||
|
"warnings": "WARNUNGEN",
|
||||||
|
"ok": "OK",
|
||||||
|
"error_one": "{n} Fehler",
|
||||||
|
"error_many": "{n} Fehler",
|
||||||
|
"warn_one": "{n} Warnung",
|
||||||
|
"warn_many": "{n} Warnungen",
|
||||||
|
"jump_first_error": "Zum ersten Fehler",
|
||||||
|
"jump_first_warn": "Zur ersten Warnung",
|
||||||
|
"filter_errors": "Filter: Fehler + Kontext",
|
||||||
|
"filter_warns": "Filter: Warnungen + Kontext",
|
||||||
|
"filter_infos": "Filter: Info + Kontext",
|
||||||
|
"filter_oks": "Filter: OK + Kontext",
|
||||||
|
"filter_clear": "Filter loeschen · alle Zeilen",
|
||||||
|
"filter_active_err": "Filter: Fehler + Kontext",
|
||||||
|
"filter_active_warn": "Filter: Warnungen + Kontext",
|
||||||
|
"filter_active_info": "Filter: Info + Kontext",
|
||||||
|
"filter_active_ok": "Filter: nur OK + Kontext",
|
||||||
|
"filter_show_all": "Alle anzeigen",
|
||||||
|
"info_one": "{n} Info",
|
||||||
|
"info_many": "{n} Info",
|
||||||
|
"ok_one": "{n} ok",
|
||||||
|
"ok_many": "{n} ok",
|
||||||
|
"env_context": "Monitoring-Umgebung",
|
||||||
|
"env_context_title": "Aufklappen: Agent-Env, Suite-Pin, Domain-Hosts und Flags",
|
||||||
|
"env_context_empty": "Kein Lauf-Header im Log",
|
||||||
|
"generated": "erzeugt",
|
||||||
|
"version": "Version",
|
||||||
|
"version_tree_link": "Git-Baum dieses Laufs oeffnen (Commit)",
|
||||||
|
"suite_version_title": "taler-monitoring Suite-Version · genauer Lauf-Baum",
|
||||||
|
"source": "Quelle",
|
||||||
|
"what_monitors": "Was diese Seite ueberwacht",
|
||||||
|
"what_monitors_title": "Aufklappen: was diese Seite prueft",
|
||||||
|
"stack_title": "Stack-Monitoring · {host}",
|
||||||
|
"stack_summary": "{phases} · public + inside",
|
||||||
|
"mode_ok": "OK",
|
||||||
|
"mode_err": "ERR",
|
||||||
|
"mode_redirect": "REDIR",
|
||||||
|
"footer": "Konsolen-Darstellung von taler-monitoring. Sticky: gruen = OK · gelb = Warnungen · rot = Fehler.",
|
||||||
|
"ago_s": "vor {n}s",
|
||||||
|
"ago_m": "vor {n} Min.",
|
||||||
|
"ago_h": "vor {n} Std.",
|
||||||
|
"ago_d": "vor {n} T.",
|
||||||
|
"age_title": "Seitenalter · jede Sekunde aktualisiert",
|
||||||
|
}
|
||||||
|
if lang == "fr":
|
||||||
|
table = fr
|
||||||
|
elif lang == "de":
|
||||||
|
table = de
|
||||||
|
else:
|
||||||
|
table = en
|
||||||
s = table.get(key) or en.get(key) or key
|
s = table.get(key) or en.get(key) or key
|
||||||
try:
|
try:
|
||||||
return s.format(**kwargs)
|
return s.format(**kwargs)
|
||||||
|
|
@ -2489,7 +2596,7 @@ def main() -> None:
|
||||||
ap.add_argument(
|
ap.add_argument(
|
||||||
"--lang",
|
"--lang",
|
||||||
default="",
|
default="",
|
||||||
help="UI language en|fr (default: env TALER_MON_LANG or auto)",
|
help="UI language en|fr|de (default: domains.conf lang / env; de never stock default)",
|
||||||
)
|
)
|
||||||
ap.add_argument(
|
ap.add_argument(
|
||||||
"--page-label",
|
"--page-label",
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ Options:
|
||||||
--merchant URL merchant-backend base — overrides profile
|
--merchant URL merchant-backend base — overrides profile
|
||||||
--currency CODE expected currency (GOA, KUDOS, CHF, …); empty = report only
|
--currency CODE expected currency (GOA, KUDOS, CHF, …); empty = report only
|
||||||
--no-probe do not probe alternate hosts (unknown domains only)
|
--no-probe do not probe alternate hosts (unknown domains only)
|
||||||
--lang en|fr UI/console language (sticky bar + badges)
|
--lang en|fr|de UI/console language (sticky bar + badges; de available, not a profile default)
|
||||||
overrides auto (FrancPaysan→fr, else en)
|
overrides auto (FrancPaysan→fr, else en)
|
||||||
--ver, --version, -V print suite version, git commit, and repo URLs
|
--ver, --version, -V print suite version, git commit, and repo URLs
|
||||||
-h, --help
|
-h, --help
|
||||||
|
|
@ -165,7 +165,8 @@ Env (same meaning):
|
||||||
SURFACE_CVE_LEVEL=warn|error bare Server-header versions default warn
|
SURFACE_CVE_LEVEL=warn|error bare Server-header versions default warn
|
||||||
(Debian package versions default error)
|
(Debian package versions default error)
|
||||||
SURFACE_CATALOG=path override surface-catalog.conf
|
SURFACE_CATALOG=path override surface-catalog.conf
|
||||||
TALER_MON_LANG=en|fr same as --lang (default en; auto fr for *lefrancpaysan*)
|
TALER_MON_LANG=en|fr|de same as --lang (profile lang from domains.conf; de never stock default)
|
||||||
|
TALER_MON_LOCALE=fr-CH|de-CH regional l10n from domains.conf locale column
|
||||||
|
|
||||||
Full load (GOA / hacktivism):
|
Full load (GOA / hacktivism):
|
||||||
./taler-monitoring.sh -d hacktivism.ch full
|
./taler-monitoring.sh -d hacktivism.ch full
|
||||||
|
|
@ -225,12 +226,13 @@ NO_PROBE=0
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--lang)
|
--lang)
|
||||||
[ $# -ge 2 ] || { echo "error: --lang needs en|fr" >&2; exit 2; }
|
[ $# -ge 2 ] || { echo "error: --lang needs en|fr|de" >&2; exit 2; }
|
||||||
_lang="$2"
|
_lang="$2"
|
||||||
case "$_lang" in
|
case "$_lang" in
|
||||||
fr|FR|fra|french) TALER_MON_LANG=fr ;;
|
fr|FR|fra|french) TALER_MON_LANG=fr ;;
|
||||||
|
de|DE|deu|ger|german|deutsch) TALER_MON_LANG=de ;;
|
||||||
en|EN|eng|english) TALER_MON_LANG=en ;;
|
en|EN|eng|english) TALER_MON_LANG=en ;;
|
||||||
*) echo "error: unknown language '$_lang' (use en or fr)" >&2; exit 2 ;;
|
*) echo "error: unknown language '$_lang' (use en, fr, or de)" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
TALER_MON_LANG_SET=1
|
TALER_MON_LANG_SET=1
|
||||||
export TALER_MON_LANG TALER_MON_LANG_SET
|
export TALER_MON_LANG TALER_MON_LANG_SET
|
||||||
|
|
@ -547,6 +549,8 @@ elif [ "${LOCAL_STACK:-0}" = "1" ] && command -v podman >/dev/null 2>&1 \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf 'target domain=%s\n' "${TALER_DOMAIN}"
|
printf 'target domain=%s\n' "${TALER_DOMAIN}"
|
||||||
|
printf ' ui_lang %s\n' "${TALER_MON_LANG:-en}"
|
||||||
|
printf ' locale %s\n' "${TALER_MON_LOCALE:-${TALER_DOMAIN_LOCALE:-?}}"
|
||||||
printf ' bank %s\n' "$BANK_PUBLIC"
|
printf ' bank %s\n' "$BANK_PUBLIC"
|
||||||
printf ' exchange %s\n' "$EXCHANGE_PUBLIC"
|
printf ' exchange %s\n' "$EXCHANGE_PUBLIC"
|
||||||
printf ' merchant %s\n' "$MERCHANT_PUBLIC"
|
printf ' merchant %s\n' "$MERCHANT_PUBLIC"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue