Files
palladium/app/locale.py
Robert Helewka ecd164ee6d feat: add locale formatting config and update notebook outputs
Add configurable locale/display formatting environment variables
(`PALLADIUM_CURRENCY_SYMBOL`, `PALLADIUM_THOUSANDS_SEP`,
`PALLADIUM_DECIMAL_SEP`) to support regional number formatting in the
Streamlit app. Update `.env.example` with documentation for these new
variables.

Also refresh `00_setup.ipynb` with current execution outputs reflecting
a live Athena connection with report templates, a selected client
(Global Guardian Insurance, ID=2), and resolved NameError in assumption
override cells.
2026-06-10 11:54:28 -04:00

88 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Locale / formatting settings for the Palladium Streamlit app.
All settings are read from environment variables (via .env) so the same
codebase can be deployed for different regions without code changes.
Environment variables
---------------------
PALLADIUM_CURRENCY_SYMBOL Default: "$"
Prefix shown before monetary values (e.g. "$", "", "£", "CAD ").
PALLADIUM_THOUSANDS_SEP Default: ","
Thousands separator used in number display (e.g. "," for Americas,
"." for continental Europe, " " for some locales).
PALLADIUM_DECIMAL_SEP Default: "."
Decimal separator (e.g. "." for Americas/UK, "," for continental Europe).
Note: Streamlit's NumberColumn ``format`` uses printf-style strings.
The ``%,`` flag (thousands separator) is supported in Streamlit ≥ 1.31.
For non-standard separators (e.g. European "." thousands / "," decimal)
the values are pre-formatted as strings and displayed in TextColumns.
"""
from __future__ import annotations
import os
def _env(key: str, default: str) -> str:
return os.environ.get(key, default).strip()
# ---------------------------------------------------------------------------
# Resolved settings (read once at import time; restart app to pick up changes)
# ---------------------------------------------------------------------------
CURRENCY_SYMBOL: str = _env("PALLADIUM_CURRENCY_SYMBOL", "$")
THOUSANDS_SEP: str = _env("PALLADIUM_THOUSANDS_SEP", ",")
DECIMAL_SEP: str = _env("PALLADIUM_DECIMAL_SEP", ".")
# True when the locale uses standard printf-compatible separators
# (i.e. "," thousands + "." decimal — the C/POSIX default).
# When False, we pre-format values as strings instead of relying on printf.
_STANDARD_LOCALE: bool = THOUSANDS_SEP == "," and DECIMAL_SEP == "."
def currency_fmt() -> str:
"""Return a Streamlit NumberColumn ``format`` string for currency.
For standard locales returns e.g. ``"$%,.0f"`` (thousands-separated,
no decimal places). For non-standard locales returns ``"%s"`` and
callers should use :func:`fmt_currency` to pre-format the value.
"""
if _STANDARD_LOCALE:
return f"{CURRENCY_SYMBOL}%,.0f"
return "%s"
def pct_fmt() -> str:
"""Return a Streamlit NumberColumn ``format`` string for percentages.
Stores the value as a fraction (01) and displays as e.g. ``"20.00%"``.
Streamlit's ``%%`` in format strings renders a literal ``%``.
"""
if _STANDARD_LOCALE:
return "%.2f%%"
return "%s"
def fmt_currency(value: float) -> str:
"""Format *value* as a currency string using the configured locale."""
if _STANDARD_LOCALE:
return f"{CURRENCY_SYMBOL}{value:,.0f}"
# Non-standard: build manually
integer_part = f"{int(abs(value)):,}".replace(",", THOUSANDS_SEP)
sign = "-" if value < 0 else ""
return f"{sign}{CURRENCY_SYMBOL}{integer_part}"
def fmt_pct(value: float) -> str:
"""Format *value* (01 fraction) as a percentage string."""
pct = value * 100
if _STANDARD_LOCALE:
return f"{pct:.2f}%"
integer_part = f"{int(pct)}"
decimal_part = f"{abs(pct) % 1:.2f}"[1:] # ".xx"
return f"{integer_part}{DECIMAL_SEP}{decimal_part[1:]}%"