Ctrl K
ComunidadGuías…

i18n/__init__.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Minimal localization helpers for BrainRotGuard."""

from __future__ import annotations

from datetime import datetime

from i18n.locales.en import TRANSLATIONS as EN_TRANSLATIONS
from i18n.locales.nb import MONTHS_SHORT as NB_MONTHS_SHORT
from i18n.locales.nb import TRANSLATIONS as NB_TRANSLATIONS

DEFAULT_LOCALE = "en"
SUPPORTED_LOCALES = {"en", "nb"}
DEFAULT_TIME_FORMAT = "locale"
SUPPORTED_TIME_FORMATS = {"locale", "12h", "24h"}

_TRANSLATIONS: dict[str, dict[str, str]] = {
    "en": EN_TRANSLATIONS,
    "nb": NB_TRANSLATIONS,
}


def normalize_locale(locale: str | None) -> str:
    """Normalize user/config locale to a supported code."""
    if not locale:
        return DEFAULT_LOCALE
    value = locale.strip().lower().replace("_", "-")
    if value in ("no", "nn", "nb-no", "no-no"):
        return "nb"
    if value.startswith("nb"):
        return "nb"
    if value.startswith("en"):
        return "en"
    return DEFAULT_LOCALE


def get_locale(config) -> str:
    """Extract normalized locale from config."""
    app = getattr(config, "app", None)
    return normalize_locale(getattr(app, "locale", DEFAULT_LOCALE))


def normalize_time_format(value: str | None) -> str:
    """Normalize configured time format to a supported value."""
    if not value:
        return DEFAULT_TIME_FORMAT
    normalized = value.strip().lower().replace("_", "").replace("-", "")
    if normalized in ("locale", "default", "auto"):
        return "locale"
    if normalized in ("12h", "12hr", "12hour", "ampm"):
        return "12h"
    if normalized in ("24h", "24hr", "24hour"):
        return "24h"
    return DEFAULT_TIME_FORMAT


def get_time_format(config) -> str:
    """Extract normalized time format from config."""
    app = getattr(config, "app", None)
    return normalize_time_format(getattr(app, "time_format", DEFAULT_TIME_FORMAT))


def t(locale: str | None, key: str, **kwargs) -> str:
    """Translate a text key with English fallback."""
    normalized = normalize_locale(locale)
    text = _TRANSLATIONS.get(normalized, {}).get(key, key)
    if kwargs:
        return text.format(**kwargs)
    return text


def app_name(locale: str | None) -> str:
    """Return the localized application name."""
    return t(locale, "App Name")


def category_label(category: str, locale: str | None, short: bool = False) -> str:
    """Return localized category label."""
    if short:
        if category == "edu":
            return t(locale, "Edu")
        return t(locale, "Fun")
    if category == "edu":
        return t(locale, "Educational")
    return t(locale, "Entertainment")


def day_label(day: str, locale: str | None, short: bool = False) -> str:
    """Return localized day label from canonical day code."""
    mapping = {
        "mon": ("Monday", "Mon"),
        "tue": ("Tuesday", "Tue"),
        "wed": ("Wednesday", "Wed"),
        "thu": ("Thursday", "Thu"),
        "fri": ("Friday", "Fri"),
        "sat": ("Saturday", "Sat"),
        "sun": ("Sunday", "Sun"),
    }
    long_key, short_key = mapping.get(day, (day, day.capitalize()[:3]))
    return t(locale, short_key if short else long_key)


def _uses_24h(locale: str | None, time_format: str | None) -> bool:
    """Decide whether to render times in 24-hour format."""
    normalized_format = normalize_time_format(time_format)
    if normalized_format == "24h":
        return True
    if normalized_format == "12h":
        return False
    return normalize_locale(locale) == "nb"


def format_time(hhmm: str | None, locale: str | None, time_format: str | None = None) -> str | None:
    """Locale-aware time formatting with optional explicit time format."""
    if hhmm is None:
        return None
    try:
        hour, minute = map(int, hhmm.split(":"))
    except (ValueError, AttributeError):
        return hhmm

    if _uses_24h(locale, time_format):
        return f"{hour:02d}:{minute:02d}"

    suffix = "AM" if hour < 12 else "PM"
    display_hour = hour % 12 or 12
    if minute == 0:
        return f"{display_hour} {suffix}"
    return f"{display_hour}:{minute:02d} {suffix}"


def format_time_compact(hhmm: str | None, locale: str | None, time_format: str | None = None) -> str | None:
    """Shorter locale-aware time formatting for compact grids."""
    if hhmm is None:
        return None
    if _uses_24h(locale, time_format):
        try:
            hour, minute = map(int, hhmm.split(":"))
        except (ValueError, AttributeError):
            return hhmm
        return f"{hour:02d}" if minute == 0 else f"{hour:02d}:{minute:02d}"
    display = format_time(hhmm, locale, time_format=time_format)
    if display is None:
        return None
    return display.replace(" AM", "a").replace(" PM", "p").replace(":00", "")


def format_month_day(date_str: str, locale: str | None) -> str:
    """Format YYYY-MM-DD as a short month/day label."""
    dt = datetime.strptime(date_str, "%Y-%m-%d")
    if normalize_locale(locale) == "nb":
        return f"{NB_MONTHS_SHORT[dt.month - 1]} {dt.day:02d}"
    return dt.strftime("%b %d")


def html_lang(locale: str | None) -> str:
    """Return HTML lang attribute value."""
    return normalize_locale(locale)


__all__ = [
    "app_name",
    "DEFAULT_LOCALE",
    "DEFAULT_TIME_FORMAT",
    "SUPPORTED_LOCALES",
    "SUPPORTED_TIME_FORMATS",
    "category_label",
    "day_label",
    "format_month_day",
    "format_time",
    "format_time_compact",
    "get_locale",
    "get_time_format",
    "html_lang",
    "normalize_locale",
    "normalize_time_format",
    "t",
]