Files
code/web/js/i18n.js
elffuss-bot 42a4a9a67c Stand-in import of elffuss/code
One parentless commit with only the files that the open seed tasks touch and the modules they import.
The full squashed import (SPEC 8.6) is a later step: this tree is not the cutoff tree.

T2T-StandIn-Source-Commit: 43f95b7333efe73aeaebf806023f17bffea27aba
2026-10-01 00:00:00 +00:00

272 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// i18n ligero del «chrome» de Elffuss Code. El modelo ya responde en el idioma
// del navegador (agent.js → userLang); esto localiza los textos estáticos y de
// runtime de la UI (placeholder, indicadores «pensando/escribe», estado del
// modelo, saludo del proyecto, la Mente). ES por defecto — cero impacto en
// usuarios españoles — con inglés de fallback. Sustitución simple {var}.
const L = {
es: {
ph: 'Escribe aquí… (@ adjunta un archivo)',
thinking: 'Elffuss está pensando', writing: 'Elffuss escribe · {n} car.', using: 'Elffuss usa {name}',
modelLoading: 'Descargando el modelo IA · {pct}% · {loaded}/{total} MB',
modelReady: 'Modelo IA listo', modelReadyBadge: 'Modelo IA listo ✳',
welcome: '👋 Proyecto «{name}» abierto. Pregúntame por el código, pídeme cambios o dime «árbol». Todo se queda en tu máquina.',
mindTitle: 'MENTE DE ELFFUSS', avatarTitle: 'Mente de Elffuss — cerebro autónomo',
// landing (estático) + tooltips de la barra/toolbar
tagline: 'Abre tu carpeta de código y programa con una elfa al lado.',
tagline2: 'Editor tipo VS Code + agente <b>en tu navegador</b>. Nada sale de tu máquina. 😉',
openProject: '📁 Abrir carpeta de código', resume: 'Reanudar', discard: 'Descartar', cloneOpen: 'Descargar y abrir',
clonePh: 'pega la URL de un repo público (GitHub/Bitbucket)…',
searchPh: 'Buscar archivos por nombre (: para ir a línea, @ para símbolo, > para comandos)',
tFiles: 'Explorador', tSearch: 'Buscar (Cmd/Ctrl+P)', tArch: 'Arquitectura (grafo de dependencias)',
tCity: 'Ciudad 3D', tTerm: 'Terminal (Ctrl+`)', tSkills: 'Skills', tActSettings: 'Ajustes y modelo',
tGitBranch: 'rama actual', tHistory: 'Historial de conversaciones', tTopSettings: 'Ajustes, modelo y API keys',
tTermClose: 'cerrar (Ctrl+`)', tTermResize: 'arrastra para redimensionar',
tCtx: 'contexto acumulado en la conversación', tPlus: 'Adjuntar archivo del proyecto (@)',
tAutoedit: 'Editar archivos automáticamente',
tHardwork: 'Hard Work: lee tu proyecto entero por partes — audita, resume o busca en código que no cabe en el modelo',
tGoal: 'Modo Objetivo: descompone el mensaje en tareas y las ejecuta una a una (planificador + ejecutor)',
tFlip: 'cambiar entre chat y editor', tSlash: 'Comandos',
// pass-3: chrome profundo del IDE (paleta, menús, historial, ajustes, notifs)
tabClose: 'Cerrar pestaña (no borra la conversación)', newConv: 'Nueva conversación',
histEmpty: 'Sin conversaciones guardadas todavía.', histDel: 'Eliminar para siempre',
confirmDel: '¿Eliminar «{title}» para siempre?', thisConv: 'esta conversación',
cmdsSep: 'Comandos', slTree: 'árbol del proyecto', slSearch: 'buscar en el código',
slSkills: 'gestionar skills', slModel: 'proveedores y modelo', slClear: 'nueva conversación',
pTree: 'árbol', pSearch: 'busca ', pCommit: 'resume los cambios y prepárame el mensaje de commit',
pProposal: 'Implementa esta propuesta de mejora con cambios reales en el código:\n\n',
attachSep: 'Adjuntar al mensaje (@)', attachOpen: 'archivo abierto', openProjFirst: 'Abre un proyecto primero',
autoTxt: 'Auto', reviewTxt: 'Revisar',
autoOn: 'Editar archivos automáticamente (clic para revisar antes)',
autoOff: 'Pedir confirmación antes de escribir (clic para automático)',
pSearchCode: 'Buscar en el código…', pManageSkills: 'Gestionar skills', pToggleExplorer: 'Alternar explorador',
pToggleTerm: 'Alternar terminal', pSave: 'Guardar (Ctrl+S)', palCmd: 'comando',
palGotoSym: 'Ir a símbolo en el editor…', palEmpty: 'Sin resultados',
mNewFile: 'Nuevo archivo…', promptNewPath: 'Ruta del nuevo archivo:', mSave: 'Guardar', mOpenFolder: 'Abrir carpeta…',
mSearchCode: 'Buscar en el código', mGotoFile: 'Ir a archivo…', mGotoSym: 'Ir a símbolo…',
mTerminal: 'Terminal', mArch: 'Arquitectura', mAbout: 'Acerca de Elffuss Code (GitHub)',
gNotRepo: 'No es un repositorio git', gBranch: 'Rama: {b}', gLast: 'Último: {m}', gCommit: 'Pídele a Elffuss que commitee',
nExec: '▶ Ejecutar', nView: 'Ver en la Mente',
fallbackToast: 'Ese Gemma no cargó (memoria/GPU) — uso Elffuss LM (ligero)…',
setStoreTitle: 'Modelo descargado (se cachea en tu navegador)', setClear: 'Vaciar caché', setClearing: 'Vaciando…',
setCached: '{gb} en caché', setNone: 'Nada cacheado todavía',
setBrToken: 'Token (lo imprime el programa al arrancarlo)', brTokenPh: 'pega aquí el token…',
setFeedbackPh: 'Cuéntanos qué ha pasado o qué te gustaría que hiciera…',
lblModel: 'Modelo', lblApiKey: 'API key',
setCalc: 'Calculando espacio…', setPersist: '✓ almacenamiento persistente (no se borra solo)',
setNoPersist: '⚠ sin persistencia: el navegador podría desalojarlo', setLimit: ' · límite ~{gb}',
setModelPh: 'modelo (p. ej. gpt-4o-mini)', keyNeeded: 'clave (no necesaria)',
wsTitle: "Espacio de trabajo (tu disco)",
wsDesc: "Tus conversaciones y skills viven en este navegador, que puede borrarlas. Guárdalas en una carpeta y quedan como ficheros normales.",
wsNoSupport: "Este navegador no permite elegir carpeta. Usa «Descargar copia».",
wsNoFolder: "Sin carpeta: solo viven en este navegador.",
wsFolder: "Carpeta: {name}",
wsNeedsPerm: "«{name}» necesita permiso otra vez (pasa al recargar).",
wsPick: "Elegir carpeta",
wsUseProject: "Usar la del proyecto",
wsRegrant: "Conceder permiso",
wsSaveNow: "Guardar ahora",
wsSaved: "Guardado ({n} almacenes)",
wsAuto: "Guardar solo",
wsForget: "Olvidar carpeta",
wsDownload: "Descargar copia",
wsWhat: "Qué hay guardado",
setTitle: "Ajustes",
close: "cerrar",
setBrainTitle: "Cerebro (modelo)",
setModelE4bSub: "El mejor · WebGPU local · ~4 GB",
setModelE2bSub: "Ligero · WebGPU local · ~2 GB",
setModelOnnxSub: "Modelo propio · 850 MB · tool-calls + apps",
setModelRulesSub: "Órdenes directas, cero descarga",
setBridgeTitle: "🔌 Bridge local (ejecución real en tu máquina)",
setBridgeDisconnected: "desconectado",
setBridgeFolderPh: "/ruta/completa/a/tu/proyecto",
setBridgeConnect: "Conectar",
setBridgeOnStatus: "✓ conectado — ejecución real activa",
setBridgeNoToken: "⚠️ pega el token que imprimió el programa al arrancarlo",
setBridgeConnecting: "Conectando…",
setBridgeConnectedMsg: "✔ conectado — ejecución real en tu máquina",
setPermTitle: "✅ Permisos de ejecución",
setGoalTitle: "🎯 Modo Objetivo",
setTelTitle: "📨 Errores y feedback",
setTelEmpty: "escribe algo primero",
setTelThanks: "¡enviado, gracias!",
setProvTitle: "Proveedores externos (opcional · la clave se queda en tu navegador)",
setProvUse: "Usar",
setManageSkillsBtn: "Gestionar skills de Claude Code",
skRemove: "Quitar",
skBrowse: "Explorar",
skAddRepoPh: "owner/repo o URL de GitHub (p. ej. OpenClaude/…)",
skAddRepo: "Añadir repo",
hwPlaceholder: "⛏ Hard Work: pregunta algo sobre TODO el proyecto…",
hwNeedBrain: "Hard Work necesita un cerebro cargado: elige un modelo en Ajustes y reintenta.",
hwNeedProject: "Hard Work trabaja sobre tu proyecto. Abre una carpeta primero y vuelve a pulsar ⛏ Hard Work.",
hwReading: "Hard Work · leyendo el proyecto…",
hwNoFiles: "No encontré archivos de texto/código legibles en el proyecto.",
hwTrimmed: " — recortado",
hwPhaseReduce: "Hard Work · sintetizando…",
hwResultTrunc: " Proyecto recortado al máximo — acota con una subcarpeta.",
planPlanning: "planificando…",
planRunning: "ejecutando…",
planDone: "completado",
planFailed: "con fallos",
stModelLoadingAI: "Cargando el modelo IA…",
termCapsBridge: "🔌 Bridge local: node/npm/python reales",
termCapsNoBridge: "shell del proyecto · node/npm/python → Bridge local (⚙ Ajustes)",
setBridgeFolderLabel: "Carpeta de trabajo (opcional — si no, usa una temporal)",
setBridgeDesc: "Un pequeño programa que TÚ ejecutas en tu ordenador — le da a la elfa ejecución real (node, npm, python…) sin salir de tu máquina. Nada se instala en el navegador.",
setBridgeDownload: "⬇ Descargar para {os}",
setBridgeOtherOS: "otro sistema operativo",
setModelRulesName: "Básico (sin modelo)",
},
en: {
ph: 'Type here… (@ attaches a file)',
thinking: 'Elffuss is thinking', writing: 'Elffuss writes · {n} chars', using: 'Elffuss uses {name}',
modelLoading: 'Downloading AI model · {pct}% · {loaded}/{total} MB',
modelReady: 'AI model ready', modelReadyBadge: 'AI model ready ✳',
welcome: '👋 Project “{name}” open. Ask me about the code, request changes, or say “tree”. Everything stays on your machine.',
mindTitle: 'ELFFUSS MIND', avatarTitle: 'Elffuss Mind — autonomous brain',
tagline: 'Open your code folder and program with an elf by your side.',
tagline2: 'VS Code–style editor + agent <b>in your browser</b>. Nothing leaves your machine. 😉',
openProject: '📁 Open code folder', resume: 'Resume', discard: 'Discard', cloneOpen: 'Download & open',
clonePh: 'paste the URL of a public repo (GitHub/Bitbucket)…',
searchPh: 'Search files by name (: to go to line, @ for symbol, > for commands)',
tFiles: 'Explorer', tSearch: 'Search (Cmd/Ctrl+P)', tArch: 'Architecture (dependency graph)',
tCity: '3D City', tTerm: 'Terminal (Ctrl+`)', tSkills: 'Skills', tActSettings: 'Settings & model',
tGitBranch: 'current branch', tHistory: 'Conversation history', tTopSettings: 'Settings, model & API keys',
tTermClose: 'close (Ctrl+`)', tTermResize: 'drag to resize',
tCtx: 'context accumulated in the conversation', tPlus: 'Attach a project file (@)',
tAutoedit: 'Edit files automatically',
tHardwork: 'Hard Work: reads your whole project in chunks — audits, summarises or searches code that does not fit in the model',
tGoal: 'Goal mode: breaks the message into tasks and runs them one by one (planner + executor)',
tFlip: 'switch between chat and editor', tSlash: 'Commands',
tabClose: 'Close tab (doesn’t delete the conversation)', newConv: 'New conversation',
histEmpty: 'No saved conversations yet.', histDel: 'Delete forever',
confirmDel: 'Delete “{title}” forever?', thisConv: 'this conversation',
cmdsSep: 'Commands', slTree: 'project tree', slSearch: 'search the code',
slSkills: 'manage skills', slModel: 'providers & model', slClear: 'new conversation',
pTree: 'tree', pSearch: 'search ', pCommit: 'summarize the changes and prepare my commit message',
pProposal: 'Implement this improvement proposal with real changes to the code:\n\n',
attachSep: 'Attach to message (@)', attachOpen: 'open file', openProjFirst: 'Open a project first',
autoTxt: 'Auto', reviewTxt: 'Review',
autoOn: 'Edit files automatically (click to review first)',
autoOff: 'Ask before writing (click for automatic)',
pSearchCode: 'Search the code…', pManageSkills: 'Manage skills', pToggleExplorer: 'Toggle explorer',
pToggleTerm: 'Toggle terminal', pSave: 'Save (Ctrl+S)', palCmd: 'command',
palGotoSym: 'Go to symbol in editor…', palEmpty: 'No results',
mNewFile: 'New file…', promptNewPath: 'New file path:', mSave: 'Save', mOpenFolder: 'Open folder…',
mSearchCode: 'Search the code', mGotoFile: 'Go to file…', mGotoSym: 'Go to symbol…',
mTerminal: 'Terminal', mArch: 'Architecture', mAbout: 'About Elffuss Code (GitHub)',
gNotRepo: 'Not a git repository', gBranch: 'Branch: {b}', gLast: 'Latest: {m}', gCommit: 'Ask Elffuss to commit',
nExec: '▶ Run', nView: 'View in the Mind',
fallbackToast: 'That Gemma didn’t load (memory/GPU) — using Elffuss LM (light)…',
setStoreTitle: 'Downloaded model (cached in your browser)', setClear: 'Clear cache', setClearing: 'Clearing…',
setCached: '{gb} cached', setNone: 'Nothing cached yet',
setBrToken: 'Token (printed by the program on startup)', brTokenPh: 'paste the token here…',
setFeedbackPh: 'Tell us what happened or what you’d like it to do…',
lblModel: 'Model', lblApiKey: 'API key',
setCalc: 'Calculating space…', setPersist: '✓ persistent storage (won’t be auto-cleared)',
setNoPersist: '⚠ not persistent: the browser could evict it', setLimit: ' · limit ~{gb}',
setModelPh: 'model (e.g. gpt-4o-mini)', keyNeeded: 'key (not needed)',
wsTitle: "Workspace (your disk)",
wsDesc: "Your conversations and skills live in this browser, which can wipe them. Save them to a folder and they stay as normal files.",
wsNoSupport: "This browser can't pick a folder. Use «Download copy».",
wsNoFolder: "No folder: they only live in this browser.",
wsFolder: "Folder: {name}",
wsNeedsPerm: "«{name}» needs permission again (happens after a reload).",
wsPick: "Pick a folder",
wsUseProject: "Use the project's",
wsRegrant: "Grant permission",
wsSaveNow: "Save now",
wsSaved: "Saved ({n} stores)",
wsAuto: "Save automatically",
wsForget: "Forget folder",
wsDownload: "Download copy",
wsWhat: "What's stored",
setTitle: "Settings",
close: "close",
setBrainTitle: "Brain (model)",
setModelE4bSub: "The best · local WebGPU · ~4 GB",
setModelE2bSub: "Light · local WebGPU · ~2 GB",
setModelOnnxSub: "Our own model · 850 MB · tool-calls + apps",
setModelRulesSub: "Direct commands, zero download",
setBridgeTitle: "🔌 Local bridge (real execution on your machine)",
setBridgeDisconnected: "disconnected",
setBridgeFolderPh: "/full/path/to/your/project",
setBridgeConnect: "Connect",
setBridgeOnStatus: "✓ connected — real execution active",
setBridgeNoToken: "⚠️ paste the token the program printed on startup",
setBridgeConnecting: "Connecting…",
setBridgeConnectedMsg: "✔ connected — real execution on your machine",
setPermTitle: "✅ Execution permissions",
setGoalTitle: "🎯 Goal mode",
setTelTitle: "📨 Errors and feedback",
setTelEmpty: "type something first",
setTelThanks: "sent, thanks!",
setProvTitle: "External providers (optional · the key stays in your browser)",
setProvUse: "Use",
setManageSkillsBtn: "Manage Claude Code skills",
skRemove: "Remove",
skBrowse: "Browse",
skAddRepoPh: "owner/repo or GitHub URL (e.g. OpenClaude/…)",
skAddRepo: "Add repo",
hwPlaceholder: "⛏ Hard Work: ask something about the WHOLE project…",
hwNeedBrain: "Hard Work needs a loaded brain: pick a model in Settings and try again.",
hwNeedProject: "Hard Work works on your project. Open a folder first, then press ⛏ Hard Work again.",
hwReading: "Hard Work · reading the project…",
hwNoFiles: "I found no readable text/code files in the project.",
hwTrimmed: " — trimmed",
hwPhaseReduce: "Hard Work · synthesizing…",
hwResultTrunc: " Project trimmed to the max — narrow it down to a subfolder.",
planPlanning: "planning…",
planRunning: "running…",
planDone: "completed",
planFailed: "with failures",
stModelLoadingAI: "Loading the AI model…",
termCapsBridge: "🔌 Local bridge: real node/npm/python",
termCapsNoBridge: "project shell · node/npm/python → Local bridge (⚙ Settings)",
setBridgeFolderLabel: "Working folder (optional — otherwise a temporary one is used)",
setBridgeDesc: "A small program that YOU run on your computer — it gives the elf real execution (node, npm, python…) without leaving your machine. Nothing is installed in the browser.",
setBridgeDownload: "⬇ Download for {os}",
setBridgeOtherOS: "another operating system",
setModelRulesName: "Basic (no model)",
},
};
// Idioma del chrome: 2 letras, ES por defecto.
export function uiLang() {
return (navigator.language || 'es').slice(0, 2).toLowerCase();
}
// Traduce una clave de runtime con sustitución {var}. Fallback: idioma →
// inglés → la propia clave.
export function t(key, vars) {
const s = (L[uiLang()] || L.en)[key] ?? L.en[key] ?? key;
return vars ? s.replace(/\{(\w+)\}/g, (_, k) => (vars[k] ?? '')) : s;
}
// Textos estáticos del HTML (landing, placeholders, tooltips) que no pasan por
// t() en runtime. Se cablean una vez al arrancar; ES es el HTML por defecto.
export function applyI18n() {
document.documentElement.lang = uiLang();
const set = (sel, prop, key) => { const e = document.querySelector(sel); if (e) e[prop] = t(key); };
set('#prompt', 'placeholder', 'ph');
const tag = document.querySelector('#landing .tag');
if (tag) tag.innerHTML = `${t('tagline')}<br>${t('tagline2')}`;
set('#open-project', 'textContent', 'openProject');
set('#resume-clone-btn', 'textContent', 'resume');
set('#discard-clone-btn', 'textContent', 'discard');
set('#clone-btn', 'textContent', 'cloneOpen');
set('#clone-url', 'placeholder', 'clonePh');
set('#pal-input', 'placeholder', 'searchPh');
const titles = {
'#act-files': 'tFiles', '#act-search': 'tSearch', '#act-arch': 'tArch', '#act-city': 'tCity',
'#act-term': 'tTerm', '#act-skills': 'tSkills', '#act-settings': 'tActSettings',
'#git-branch': 'tGitBranch', '#btn-history': 'tHistory', '#btn-settings': 'tTopSettings',
'#term-close': 'tTermClose', '#term-resize': 'tTermResize', '#ctx-meter': 'tCtx',
'#btn-plus': 'tPlus', '#btn-autoedit': 'tAutoedit', '#btn-goal': 'tGoal',
'#btn-hardwork': 'tHardwork',
'#code-flip': 'tFlip', '#btn-slash': 'tSlash',
};
for (const [sel, key] of Object.entries(titles)) set(sel, 'title', key);
}