lib.i18n

Internacionalización: función _() para CLI y GUI.

Prioridad de idioma: config (~/.config/temario/temario.yaml) → TEMARIO_LANG (variable de entorno) → LANG del sistema → fallback (español, idioma fuente)

Uso:

from lib.i18n import _ # en cualquier módulo import lib.i18n as i18n; i18n.setup() # una vez al inicio de la app (main.py / __main__) print(_("hola"))

 1"""
 2Internacionalización: función _() para CLI y GUI.
 3
 4Prioridad de idioma: config (~/.config/temario/temario.yaml)
 5                   → TEMARIO_LANG (variable de entorno)
 6                   → LANG del sistema
 7                   → fallback (español, idioma fuente)
 8
 9Uso:
10    from lib.i18n import _           # en cualquier módulo
11    import lib.i18n as i18n; i18n.setup()   # una vez al inicio de la app (main.py / __main__)
12    print(_("hola"))
13"""
14
15import builtins
16import gettext
17import os
18from pathlib import Path
19
20_LOCALES_DIR = Path(__file__).parent.parent / 'locales'
21_DOMAIN      = 'escriba'
22
23_gettext_func = lambda s: s   # identidad hasta que setup() se llame
24
25
26def _(s: str) -> str:  # noqa: E743  (nombre corto intencionado)
27    """Traduce s al idioma activo. No-op hasta que setup() sea llamado."""
28    return _gettext_func(s)
29
30
31def _detect_lang() -> str | None:
32    """Detecta el idioma a usar: config → ESCRIBA_LANG → LANG del sistema."""
33    try:
34        from lib.slides_config import get_language
35        lang = get_language()
36        if lang:
37            return lang
38    except Exception:
39        pass
40    if env := os.environ.get('ESCRIBA_LANG', '').strip():
41        return env
42    system = os.environ.get('LANG', '').split('_')[0].split('.')[0].lower()
43    return system or None
44
45
46def setup(lang: str | None = None) -> None:
47    """Activa la traducción. Llamar una vez al inicio de la app."""
48    global _gettext_func
49    if lang is None:
50        lang = _detect_lang()
51    t = gettext.translation(
52        _DOMAIN,
53        localedir=str(_LOCALES_DIR),
54        languages=[lang] if lang else None,
55        fallback=True,
56    )
57    _gettext_func = t.gettext
58    builtins._ = _   # disponible globalmente para módulos que no importen i18n
59
60
61# Instalar identidad en builtins como fallback (antes de setup())
62if not hasattr(builtins, '_'):
63    builtins._ = _
def setup(lang: str | None = None) -> None:
47def setup(lang: str | None = None) -> None:
48    """Activa la traducción. Llamar una vez al inicio de la app."""
49    global _gettext_func
50    if lang is None:
51        lang = _detect_lang()
52    t = gettext.translation(
53        _DOMAIN,
54        localedir=str(_LOCALES_DIR),
55        languages=[lang] if lang else None,
56        fallback=True,
57    )
58    _gettext_func = t.gettext
59    builtins._ = _   # disponible globalmente para módulos que no importen i18n

Activa la traducción. Llamar una vez al inicio de la app.