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
This commit is contained in:
271
web/js/i18n.js
Normal file
271
web/js/i18n.js
Normal file
@@ -0,0 +1,271 @@
|
||||
// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user