Internacionalización (i18n)

Architect CLI soporta inglés (default) y español para todos los mensajes generados por el sistema: logs humanos, prompts de agentes, reportes, guardrails y evaluaciones.

v1.1.0: Los mensajes del sistema ahora están en inglés por defecto. Se puede cambiar a español via configuración.


Configuración

Via YAML

# config.yaml (o .architect.yaml)
language: es   # "en" (default) | "es"

Via variable de entorno

export ARCHITECT_LANGUAGE=es

Via código (para extensiones)

from architect.i18n import set_language, get_language

set_language("es")
print(get_language())  # "es"

Precedencia

1. Defaults del código → "en"

2. Archivo YAML → language: es

3. Variable de entorno → ARCHITECT_LANGUAGE=es

Qué cambia con el idioma

ComponenteAfectado por languageEjemplo ENEjemplo ES
Logs HUMAN (stderr)Step 1 → LLM callPaso 1 → Llamada al LLM
Agent prompts (system)You are a careful executor...Eres un ejecutor cuidadoso...
Reportes (markdown/JSON)## Code Health Delta## Delta de Salud del Código
Guardrails messagesSensitive file blocked...Archivo sensible bloqueado...
Close instructionsYour budget is exhausted...Tu presupuesto se ha agotado...
Context summaries[Summary of previous steps][Resumen de pasos anteriores]
Self-evaluator promptsOriginal task:Tarea original:
Ralph Loop progress# Ralph Loop — Progress# Ralph Loop — Progreso
CLI help/flagsNo--mode yolo--mode yolo
User promptsNo(sin cambio)(sin cambio)
Error messages (CLI)No(siempre inglés)(siempre inglés)

Qué NO cambia

  • CLI help text: architect --help, architect run --help, etc. siempre están en inglés.
  • Prompts del usuario: el texto que el usuario escribe no se traduce.
  • Skills y .architect.md: el contenido de los archivos del proyecto no se traduce.
  • Nombres de archivos: SKILL.md, memory.md, etc. mantienen sus nombres.
  • Formato JSON de salida: las claves JSON (status, final_output, etc.) no cambian.

Arquitectura

Módulo src/architect/i18n/

src/architect/i18n/
├── __init__.py    # API pública: t(), set_language(), get_language(), get_prompt()
├── registry.py    # LanguageRegistry — singleton thread-safe con fallback chain
├── en.py          # Strings en inglés (canónico, ~160 keys)
└── es.py          # Strings en español (~160 keys)

API pública

FunciónDescripción
t(key, **kwargs)Traduce una key con interpolación opcional
get_prompt(key)Obtiene un prompt multilinea para el idioma actual
set_language(lang)Establece el idioma activo ("en" o "es")
get_language()Retorna el código del idioma actual

Cadena de fallback

Cuando se busca una key, el registry sigue esta cadena:

idioma actual → inglés (fallback) → key cruda (último recurso)

Esto garantiza que nunca se rompe la aplicación aunque falte una traducción: si una key no existe en español, se usa la versión inglesa. Si tampoco existe en inglés, se retorna la key como string.

Resolución lazy

Todas las traducciones se resuelven en runtime, no en import-time. Esto es crítico porque set_language() se llama después de que los módulos se importen (cuando se carga la configuración del usuario).

Los mecanismos lazy incluyen:

  • _PromptProxy en agents/prompts.py: DEFAULT_PROMPTS["build"] resuelve via get_prompt() en cada acceso.
  • _LazyAgentDict en agents/registry.py: DEFAULT_AGENTS["build"] construye el AgentConfig con el prompt del idioma actual.
  • _LazyPrompt y _LazyStr: wrappers para REVIEW_SYSTEM_PROMPT y BUILD_PROMPT que resuelven en .format() o str().

Namespaces de keys

Las ~160 keys están organizadas en 14 namespaces:

NamespaceKeysQué cubre
human.*~41HumanFormatter: logs de pasos, tools, safety nets, pipeline, ralph, reviewer, parallel, competitive, contexto
competitive.*~17Reporte de evaluación competitiva: headers, ranking, detalles
ralph.*~16Progreso de iteraciones, prompts de especificación
eval.*~15Self-evaluator: prompt del sistema, labels, correcciones
health.*~14Delta de salud del código: título, headers, métricas
dispatch.*~13Sub-agentes: prompts, instrucciones, tipos
guardrail.*~10Mensajes de bloqueo: sensible, protegido, comandos, límites
context.*~9Resumen de contexto, headers, mensajes de omisión
pipeline.*~7Validación de pipeline YAML: errores
close.*~5Instrucciones de cierre: budget, max_steps, timeout, context_full, interrupt
prompt.*~5System prompts de agentes: build, plan, resume, review
reviewer.*~5Auto-reviewer: prompt del sistema, labels
dryrun.*~3Resumen de dry-run: headers, labels
misc.*Headers de skills, labels de pipeline

Ejemplo de uso

Cambiar idioma en config

# config.yaml
language: es

llm:
  model: gpt-4o
architect run "analiza el proyecto" --mode yolo
# Los logs en stderr se muestran en español:
# 🔄 Paso 1 → Llamada al LLM (5 mensajes)
#    ✓ LLM respondió con 2 tool calls
# ...
# ✅ Agente completado (3 pasos)

Cambiar idioma con env var

ARCHITECT_LANGUAGE=es architect run "analiza el proyecto" --mode yolo

Verificar idioma por código

from architect.i18n import t, set_language

# English (default)
print(t("human.llm_call", step=1, messages=5))
# → "\n🔄 Step 1 → LLM call (5 messages)"

set_language("es")
print(t("human.llm_call", step=1, messages=5))
# → "\n🔄 Paso 1 → Llamada al LLM (5 mensajes)"

Añadir un nuevo idioma

Para añadir soporte de un tercer idioma (por ejemplo, francés):

1. Crear el archivo de strings

# src/architect/i18n/fr.py
"""French language strings for architect-cli."""

STRINGS: dict[str, str] = {
    "human.llm_call": "\n🔄 Étape {step} → Appel LLM ({messages} messages)",
    "human.llm_response_tools": "   ✓ LLM a répondu avec {count} appel{s} d'outil",
    # ... todas las ~160 keys
}

2. Registrar en el registry

# src/architect/i18n/registry.py — en _load_defaults()
def _load_defaults(self):
    from . import en, es, fr
    self._languages["en"] = en.STRINGS
    self._languages["es"] = es.STRINGS
    self._languages["fr"] = fr.STRINGS

3. Actualizar el schema de config

# src/architect/config/schema.py
class AppConfig(BaseModel):
    language: Literal["en", "es", "fr"] = "en"

4. Verificar paridad de keys

from architect.i18n.en import STRINGS as EN
from architect.i18n.fr import STRINGS as FR

missing = set(EN) - set(FR)
extra = set(FR) - set(EN)
assert not missing, f"Missing in FR: {missing}"
assert not extra, f"Extra in FR: {extra}"

Archivos relacionados

ArchivoRol
src/architect/i18n/__init__.pyAPI pública
src/architect/i18n/registry.pyLanguageRegistry singleton
src/architect/i18n/en.pyStrings inglés (~160 keys)
src/architect/i18n/es.pyStrings español (~160 keys)
src/architect/config/schema.pyCampo language: Literal["en", "es"] en AppConfig
src/architect/config/loader.pyLectura de ARCHITECT_LANGUAGE env var
src/architect/cli.pyset_language(config.language) al inicio
tests/test_i18n/test_i18n.py~25 tests del sistema i18n