Repository navigation
Description
Objetivo y motivo
Mostrar la interfaz de Quorb en español o inglés, con español por defecto y
selección persistente en la ventana Ajustes existente.
Alcance
Incluye UI React, bandeja/notificaciones Rust, accesibilidad, formatos y errores
propios. Sin roles/panel nuevo, autodetección del SO, idiomas adicionales ni
traducción de contenido del usuario, nombres de modelos o errores externos crudos.
Dependencias y decisiones
Sin dependencia del port macOS. Elegir diccionarios tipados frente a librería y
política de fallback durante L0; ambas decisiones pendientes, no bloquear Windows
por validación Mac. Valores de locale ausentes/no soportados saneados a es.
Criterios de aceptación
- Inventario completo de textos React/Rust y decisión de traducción/fallback.
- Locale
es|enpersistido; arranque limpio y configuración antigua usanes. - Selector en Ajustes actualiza todas las ventanas y textos nativos.
- Formatos coherentes por locale sin cambiar cantidades ni contenido externo.
- No pérdida de configuración, historial, credenciales ni sesión al cambiar.
- Tests deterministas y auditoría funcional Windows con evidencia; Mac
coordinado cuando el port esté disponible, sin bloquear Windows.
Orientación y comprobaciones
Entradas: src/Settings.tsx, src/lib/format.ts, src-tauri/src/config.rs y
src-tauri/src/lib.rs (config-changed). Validar npm test,
npm run typecheck, npm run build, cargo test en src-tauri y prueba manual
Windows. Son comprobaciones planificadas, no ejecutadas.
Plan ODD cercano
| Fase | Resultado | Dependencia | Validación y salida |
|---|---|---|---|
| Observar/decidir L0 | Inventario trazable y decisión catálogos/librería/fallback | Ninguna | Contraste path:line; decisiones registradas y aceptadas |
| Desarrollar L1 | Locale persistido | L0 | Tests primero: es/en/ausente/inválido/recarga preservando datos |
| Desarrollar L2/L3 | Catálogos y selector global | L1 | Tests de claves/fallback/sincronización y selección persistente |
| Desarrollar L4 | Formatos y errores propios | L2 | Casos por locale, sin alterar valores ni errores externos |
| Verificar L5 | Auditoría completa | L3/L4 | Suite y prueba Windows reales; pendientes Mac explícitos |
Coordinación y entrega
Primer objetivo nuevo recomendado; planificada, no lista hasta cerrar L0.
Sin assignee inicial. Antes de empezar, revisar dependencias, comentarios,
assignees y PR; asignar solo ante inicio explícito. Tests y docs con su unidad;
seguir CONTRIBUTING, pedir autorización antes de diffs sobredimensionados.
Crear issue no autoriza implementar, abrir PR ni fusionar.
Activity
danielgap commentedon Oct 19, 2026
@egdev6 ¿podemos arrancar con #66? Soy danielgap (cuenta autenticada con la que trabajaría; contribuyo asistido por agente con la skill ODD del repo).
Revalidé antes de pedir la toma: issue sin assignees, sin comentarios de toma y sin PRs abiertas que la solapen. Sin dependencia del port macOS según el ODD vigente.
Petición: no tengo permisos para autoasignarme. ¿Me asignás, o preferís acordar explícitamente la coordinación? No la considero tomada hasta tu confirmación.
Entrada L0 que propongo ejecutar (según el ODD del issue):
path:line(src/Settings.tsx,src/lib/format.ts,src-tauri/src/config.rs,src-tauri/src/lib.rscomo entradas).esde locales ausentes/inválidos.Sin implementación hasta que ambas decisiones estén registradas y aceptadas. Si ves solapamiento o preferís otro orden, lo coordino contigo.
egdev6 commentedon Oct 19, 2026
Adelante! toda tuya! si la tarea no está asignada a nadie está libre para su toma...dale candela @danielgap !!
danielgap commentedon Oct 19, 2026
L0 — Inventario y decisiones (propuesta) · @egdev6
Cerré la entrada L0 del ODD, sin implementación aún. Inventario sobre
main@3864613: ~700 literales en ~850 sitios con contrastepath:line(React ~494 · Rust ~206: bandeja, diálogos nativos, errores de proveedores y labels de meters). El detalle acompaña al PR de L1 como documento.A · Catálogos tipados, sin librería i18n —
es.ts/en.tscon contrato de tipos (clave faltante = error de compilación), enum de claves +matchexhaustivo en Rust, e ids estables cruzando la frontera Rust→JS (hoyMeter.labelse empareja por literal enshortLabel; con dos idiomas eso se rompe). Test de paridad de placeholders en vitest;Intlcon mapa cerradoes→es-ES/en→en-US; plurales (2 casos) por ramificación. Evalué las alternativas vivas hoy (i18next 26, Lingui 6, Paraglide 2, Fluent, react-intl, rust-i18n): ninguna cubre la mitad Rust ni los textos que viajan como datos, yfluent-reactlleva congelado desde 2022.B · Fallback saneando a
es—locale: "es"|"en"enAppConfig: clave ausente o arranque limpio →es; valor no soportado →estras normalizar; error de parseo → default existente; render eIntlnunca fallan abiertos. Sin migración: las configs actuales cargan igual. Bandeja y títulos se reconstruyen en runtime al cambiar idioma (verificado contra tauri 2.12).¿Apruebas A y B para arrancar L1 (locale persistido)?
egdev6 commentedon Oct 20, 2026
@egdev6 @danielgap — revisé la propuesta L0 contra
main@3864613. Veredicto: aprobados A y B para arrancar L1, con el documento de inventario como condición de revisión del PR.Claims verificados en código ✅
El hallazgo del emparejamiento por literal es real y crítico — es el punto que justifica los ids estables:
src/lib/format.ts:42—shortLabel()con mapa literal ('Semana · todos': 'Semana', …); con textos traducidos se cae silenciosamente al fallback?? label.replace(...).src/lib/alerts.ts:68— el diff de alertas comparax.label === m.labelentre reportes previos y nuevos: cambiar el idioma rompe la comparación (alertas fantasma o perdidas).src/lib/meter-colors.ts:15-16— regex sobre literales españoles (^semana\b,^sesión\b) para elegir el color del anillo.src-tauri/src/providers/codex.rs:147— Rust emite"Semana"como dato, confirmando que textos Rust viajan como datos a JS.Los ids estables Rust→JS son, por tanto, prerrequisito de L1/L2 y no un refinamiento posterior. También verificable:
fluent-reactsigue congelado desde 2022, y ninguna librería viva cubre la mitad Rust ni los textos que viajan como datos — la decisión A (catálogos tipados +matchexhaustivo + test de paridad de placeholders) me parece la correcta.B está alineada con la issue:
locale: "es"|"en"enAppConfigcon saneo aeses exactamente lo planificado, sin migración de configs existentes.Matices para el PR de L1⚠️
path:lineprometido como documento adjunto.localeparseado pero null/vacío, no solo "clave ausente".es.tsdebe nacer de los literales existentes, no de una retraducción.Con eso, adelante con L1 (locale persistido) con tests primero es/en/ausente/inválido/recarga preservando datos, según el plan ODD de la issue.
fix(i18n): anchor the inventory to source trees, not a commit id (egd…
docs(config): cross-reference the locale contract with types.ts (egde…
feat(i18n): persistir el idioma de la interfaz e inventario reproduci…
feat(i18n): ids estables de medidores entre Rust y JS (L2 #66) (#159)
egdev6 commentedon Oct 21, 2026
Registro de avance del gate de L2 (fase ids estables Rust→JS) — cubierta y fusionada:
main(749a051, 2026-10-21): los 22 constructores deproviders/*.rsfijanMeter.idestable; la lógica JS (format.ts,alerts.ts,meter-colors.ts,ProviderDetails.tsx,ProviderCard.tsx) ya no compara textos en español; historial y memoria de alertas migran sin pérdida.cargo test238/238,vitest620/620,tsc --noEmitOK, check de inventario en verde en CI (incluido tras los merges de ci(i18n): fallar si el inventario de textos está desactualizado (#155) #158 y feat(i18n): ids estables de medidores entre Rust y JS (L2 #66) #159).Siguiente paso de L2/L3 (según lo anunciado en #159): catálogos y selector de medidores — el
idestable ya está como base. Dos seguimientos heredados quedaron en #160 (test de contrato del inventario, ruido de diffs) y las coberturas de id sin test dedicado en providers async (anthropic_api, openai_api, copilot) pueden integrarse en ese mismo PR.fix(i18n): fictional channel fixture and draft reconcile on failed lo…
docs(i18n): regenerate inventory after merge with main (egdev6#66)
2 remaining items
merge: integrar main (rustfmt egdev6#185) en la rama del slice 1 (egd…
chore(i18n): regenerar inventario sobre main integrado (egdev6#66)
feat(i18n): migrar la tira y el detalle a los catálogos ES/EN — T2c s…
merge: integrar main en la rama del slice 2 PR-A (egdev6#66)
chore(i18n): regenerar inventario sobre main integrado (egdev6#66)
test(i18n): updates-section merge guard resolves catalog texts (egdev…
feat(i18n): migrar las secciones no-provider de Ajustes a los catálog…
feat(i18n): migrar el armazón de la página de Proveedores a los catál…
danielgap commentedon Oct 29, 2026
@egdev6 sigo con C1 (paneles de suscripciones y editores de cuentas) sobre
main4f5fb48. Mide unos 190 textos, así que lo parto en dos PRs para que cada una se pueda revisar:CliConnectyAccountEditor, que usan todas las cuentas adicionales. Incluye tu nota 1 de feat(i18n): migrar el armazón de la página de Proveedores a los catálogos ES/EN — T2c slice 2 PR-B (#66) #204: unwhereKeyenCLI_INSTALL, para no comparar'una terminal'.aria-current/aria-expanded) y 4 (eltque tapa at()enProviderDrawerHead).Va primero C1a porque C1b usa
CliConnect. Mismas reglas que en #199/#204: conestodo se ve igual, y marcas, rutas y comandos quedan literales. C2 (OpenRouter, NaN, 9Router y APIs) queda para después.egdev6 commentedon Oct 29, 2026
@danielgap adelante con C1 tal como lo planteas: primero C1a y luego C1b. El orden encaja, porque C1b usa
CliConnect, y partirlo en dos deja cada PR en un tamaño revisable. También recoge las notas 1, 3 y 4 de #204. La nota 2 (placeholders deSecretInputen inglés dentro de paneles en español) se resuelve sola al completar C1b y C2.Coordinación con Antigravity (#207)
@eichhorn-micaela, para que lo tengas en cuenta: #207 añade un panel de suscripción nuevo (Antigravity) con sus textos en español literal: kicker, nota y pasos. Es el mismo caso que OpenCode Go en #201, así que aplicamos la misma regla:
es.ts/en.ts, español verbatim y marcas o rutas literales).Mientras tanto, la revisión de C1a sigue su curso en #216.
Merge main into feat/i18n-t2c-c1a-shared (egdev6#66)
docs: regenerar el inventario i18n tras integrar main (egdev6#66)
feat(i18n): migrar CliConnect y el editor de cuentas a los catálogos …
feat(i18n): migrar los paneles de suscripción a los catálogos ES/EN —…
danielgap commentedon Nov 7, 2026
@egdev6 retomo #66 con C2, último tramo del slice 2: paneles de APIs (OpenRouter, NaN Builders, 9Router, Anthropic API, OpenAI API) y las conexiones
NanConnect/NanProbe/NineRouterConnect, sobremain79ee3cd. Mide ~110 literales; mismo formato que C1a/C1b (catálogos ES/EN conesverbatim, tests SSR es/en, inventario regenerado).Notas:
LocalePickersolo muestra nombres nativos por diseño, sin deuda nueva de catálogo.Con C2 cierra el slice 2; después queda el slice 3 (textos de Rust que llegan a la UI). Arranco C2 en local.