feat: funciones Python core — parsers, formatters, retry, serialización, LLM utils y más
178 archivos: módulo core.py actualizado + ~80 funciones nuevas con tests. Incluye: parse_llm_json, extract_text_from_file, retry_with_backoff, circuit_breaker, from_csv/to_csv, from_jsonl/to_jsonl, html_to_markdown, pdf_to_markdown, docx/epub/excel converters, cache_decorator, react_loop, task_manager, template rendering, entre otros. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"""Traduccion de claves con dot-path notation e interpolacion de variables."""
|
||||
|
||||
import threading
|
||||
|
||||
_locale_local = threading.local()
|
||||
_translations: dict = {}
|
||||
_default_locale: str = "en"
|
||||
|
||||
|
||||
def _set_translations(translations: dict, default_locale: str = "en") -> None:
|
||||
"""Configura el diccionario global de traducciones y el locale default.
|
||||
|
||||
Llamar desde load_translations o al inicio de la aplicacion.
|
||||
"""
|
||||
global _translations, _default_locale
|
||||
_translations = translations
|
||||
_default_locale = default_locale
|
||||
|
||||
|
||||
def _set_locale(locale: str) -> None:
|
||||
"""Establece el locale para el thread actual."""
|
||||
_locale_local.locale = locale
|
||||
|
||||
|
||||
def _get_locale() -> str:
|
||||
"""Retorna el locale del thread actual, o el default si no esta configurado."""
|
||||
return getattr(_locale_local, "locale", _default_locale)
|
||||
|
||||
|
||||
def _resolve_key(translations: dict, locale: str, key: str) -> str | None:
|
||||
"""Navega dot-path en el diccionario de traducciones para un locale.
|
||||
|
||||
Returns:
|
||||
El string de traduccion si existe, None si no.
|
||||
"""
|
||||
locale_dict = translations.get(locale)
|
||||
if not locale_dict:
|
||||
return None
|
||||
|
||||
parts = key.split(".")
|
||||
node = locale_dict
|
||||
for part in parts:
|
||||
if not isinstance(node, dict):
|
||||
return None
|
||||
node = node.get(part)
|
||||
if node is None:
|
||||
return None
|
||||
|
||||
return node if isinstance(node, str) else None
|
||||
|
||||
|
||||
def t(key: str, locale: str | None = None, **kwargs) -> str:
|
||||
"""Traduce una clave con dot-path notation al idioma actual.
|
||||
|
||||
Determina el locale en orden de prioridad: parametro > thread-local > default.
|
||||
Soporta interpolacion de variables con {nombre} en el valor traducido.
|
||||
Si la clave no existe en el locale solicitado, intenta el locale default.
|
||||
Si tampoco existe, retorna la clave tal cual.
|
||||
|
||||
Args:
|
||||
key: Clave de traduccion en dot-path notation (ej: "report.taskStarted").
|
||||
locale: Locale a usar. Si es None usa el locale del thread actual.
|
||||
**kwargs: Variables para interpolar en el string traducido.
|
||||
|
||||
Returns:
|
||||
String traducido con variables interpoladas, o la key si no se encontro.
|
||||
|
||||
Example:
|
||||
>>> # translations = {"en": {"report": {"sectionStart": "Section: {title}"}}}
|
||||
>>> t("report.sectionStart", locale="en", title="Introduction")
|
||||
'Section: Introduction'
|
||||
>>> t("nonexistent.key", locale="en")
|
||||
'nonexistent.key'
|
||||
"""
|
||||
resolved_locale = locale if locale is not None else _get_locale()
|
||||
|
||||
value = _resolve_key(_translations, resolved_locale, key)
|
||||
|
||||
if value is None and resolved_locale != _default_locale:
|
||||
value = _resolve_key(_translations, _default_locale, key)
|
||||
|
||||
if value is None:
|
||||
return key
|
||||
|
||||
if kwargs:
|
||||
try:
|
||||
value = value.format(**kwargs)
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
||||
return value
|
||||
Reference in New Issue
Block a user