Internationalization (i18n)
Architect CLI supports English (default) and Spanish for all system-generated messages: human logs, agent prompts, reports, guardrails, and evaluations.
v1.1.0: System messages are now in English by default. You can switch to Spanish via configuration.
Configuration
Via YAML
# config.yaml (or .architect.yaml)
language: es # "en" (default) | "es"
Via environment variable
export ARCHITECT_LANGUAGE=es
Via code (for extensions)
from architect.i18n import set_language, get_language
set_language("es")
print(get_language()) # "es"
Precedence
1. Code defaults → "en"
↓
2. YAML file → language: es
↓
3. Environment variable → ARCHITECT_LANGUAGE=es
What changes with language
| Component | Affected by language | EN Example | ES Example |
|---|---|---|---|
| HUMAN Logs (stderr) | Yes | Step 1 → LLM call | Paso 1 → Llamada al LLM |
| Agent prompts (system) | Yes | You are a careful executor... | Eres un ejecutor cuidadoso... |
| Reports (markdown/JSON) | Yes | ## Code Health Delta | ## Delta de Salud del Código |
| Guardrails messages | Yes | Sensitive file blocked... | Archivo sensible bloqueado... |
| Close instructions | Yes | Your budget is exhausted... | Tu presupuesto se ha agotado... |
| Context summaries | Yes | [Summary of previous steps] | [Resumen de pasos anteriores] |
| Self-evaluator prompts | Yes | Original task: | Tarea original: |
| Ralph Loop progress | Yes | # Ralph Loop — Progress | # Ralph Loop — Progreso |
| CLI help/flags | No | --mode yolo | --mode yolo |
| User prompts | No | (no change) | (no change) |
| Error messages (CLI) | No | (always English) | (always English) |
What does NOT change
- CLI help text:
architect --help,architect run --help, etc. are always in English. - User prompts: the text the user writes is not translated.
- Skills and
.architect.md: project file content is not translated. - File names:
SKILL.md,memory.md, etc. keep their names. - JSON output format: JSON keys (
status,final_output, etc.) do not change.
Architecture
Module src/architect/i18n/
src/architect/i18n/
├── __init__.py # Public API: t(), set_language(), get_language(), get_prompt()
├── registry.py # LanguageRegistry — thread-safe singleton with fallback chain
├── en.py # English strings (canonical, ~160 keys)
└── es.py # Spanish strings (~160 keys)
Public API
| Function | Description |
|---|---|
t(key, **kwargs) | Translate a key with optional interpolation |
get_prompt(key) | Get a multiline prompt for the current language |
set_language(lang) | Set the active language ("en" or "es") |
get_language() | Return the current language code |
Fallback chain
When looking up a key, the registry follows this chain:
current language → English (fallback) → raw key (last resort)
This guarantees the application never breaks even if a translation is missing: if a key doesn’t exist in Spanish, the English version is used. If it doesn’t exist in English either, the key is returned as a string.
Lazy resolution
All translations are resolved at runtime, not at import-time. This is critical because set_language() is called after modules are imported (when the user’s configuration is loaded).
Lazy mechanisms include:
_PromptProxyinagents/prompts.py:DEFAULT_PROMPTS["build"]resolves viaget_prompt()on each access._LazyAgentDictinagents/registry.py:DEFAULT_AGENTS["build"]builds the AgentConfig with the current language’s prompt._LazyPromptand_LazyStr: wrappers forREVIEW_SYSTEM_PROMPTandBUILD_PROMPTthat resolve on.format()orstr().
Key namespaces
The ~160 keys are organized into 14 namespaces:
| Namespace | Keys | What it covers |
|---|---|---|
human.* | ~41 | HumanFormatter: step logs, tools, safety nets, pipeline, ralph, reviewer, parallel, competitive, context |
competitive.* | ~17 | Competitive evaluation report: headers, ranking, details |
ralph.* | ~16 | Iteration progress, specification prompts |
eval.* | ~15 | Self-evaluator: system prompt, labels, corrections |
health.* | ~14 | Code health delta: title, headers, metrics |
dispatch.* | ~13 | Sub-agents: prompts, instructions, types |
guardrail.* | ~10 | Block messages: sensitive, protected, commands, limits |
context.* | ~9 | Context summary, headers, omission messages |
pipeline.* | ~7 | Pipeline YAML validation: errors |
close.* | ~5 | Close instructions: budget, max_steps, timeout, context_full, interrupt |
prompt.* | ~5 | Agent system prompts: build, plan, resume, review |
reviewer.* | ~5 | Auto-reviewer: system prompt, labels |
dryrun.* | ~3 | Dry-run summary: headers, labels |
misc.* | — | Skills headers, pipeline labels |
Usage examples
Change language in config
# config.yaml
language: es
llm:
model: gpt-4o
architect run "analyze the project" --mode yolo
# Logs on stderr are shown in Spanish:
# 🔄 Paso 1 → Llamada al LLM (5 mensajes)
# ✓ LLM respondió con 2 tool calls
# ...
# ✅ Agente completado (3 pasos)
Change language with env var
ARCHITECT_LANGUAGE=es architect run "analyze the project" --mode yolo
Verify language via code
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)"
Adding a new language
To add support for a third language (for example, French):
1. Create the strings file
# 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",
# ... all ~160 keys
}
2. Register in the registry
# src/architect/i18n/registry.py — in _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. Update the config schema
# src/architect/config/schema.py
class AppConfig(BaseModel):
language: Literal["en", "es", "fr"] = "en"
4. Verify key parity
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}"
Related files
| File | Role |
|---|---|
src/architect/i18n/__init__.py | Public API |
src/architect/i18n/registry.py | LanguageRegistry singleton |
src/architect/i18n/en.py | English strings (~160 keys) |
src/architect/i18n/es.py | Spanish strings (~160 keys) |
src/architect/config/schema.py | language: Literal["en", "es"] field in AppConfig |
src/architect/config/loader.py | ARCHITECT_LANGUAGE env var reading |
src/architect/cli.py | set_language(config.language) at startup |
tests/test_i18n/test_i18n.py | ~25 tests for the i18n system |