From 19c4841afc0ea6ed9d569acaac3ef41275d6bb26 Mon Sep 17 00:00:00 2001 From: Anibal Angulo Date: Sun, 9 Nov 2025 11:14:42 -0600 Subject: [PATCH] localize UI to english --- frontend/src/components/ChatTab.tsx | 65 ++++++----- frontend/src/components/DashboardTab.tsx | 54 ++++----- frontend/src/components/DataroomView.tsx | 8 +- .../src/components/DeleteConfirmDialog.tsx | 38 +++---- frontend/src/components/FilesTab.tsx | 68 ++++++------ frontend/src/components/PDFPreviewModal.tsx | 103 +++++++----------- frontend/src/components/Sidebar.tsx | 66 ++++++----- .../appendonlydir/appendonly.aof.1.incr.aof | 68 ++++++++++++ redis_data/dump.rdb | Bin 7276 -> 13886 bytes 9 files changed, 249 insertions(+), 221 deletions(-) diff --git a/frontend/src/components/ChatTab.tsx b/frontend/src/components/ChatTab.tsx index ef824bd..44f7699 100644 --- a/frontend/src/components/ChatTab.tsx +++ b/frontend/src/components/ChatTab.tsx @@ -16,7 +16,7 @@ import { PromptInputTools, } from "@/components/ai-elements/prompt-input"; import { Action, Actions } from "@/components/ai-elements/actions"; -import { Fragment, useState, useEffect } from "react"; +import { Fragment, useState, useEffect, useMemo } from "react"; import { useChat } from "@ai-sdk/react"; import { Response } from "@/components/ai-elements/response"; import { @@ -56,7 +56,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { }, }), onError: (error) => { - setError(`Error en el chat: ${error.message}`); + setError(`Chat error: ${error.message}`); }, }); @@ -84,20 +84,32 @@ export function ChatTab({ selectedTema }: ChatTabProps) { { body: { dataroom: selectedTema, - context: `Usuario está consultando sobre el dataroom: ${selectedTema}`, + context: `User is asking about the dataroom: ${selectedTema}`, }, }, ); setInput(""); }; + const hasActiveToolRequest = useMemo(() => { + return messages.some((message) => + message.parts.some( + (part: any) => + typeof part?.type === "string" && + part.type.startsWith("tool-") && + part.state === "input-available", + ), + ); + }, [messages]); + + const shouldShowGlobalLoader = + (status === "streaming" || status === "loading") && !hasActiveToolRequest; + if (!selectedTema) { return (
-

- Selecciona un dataroom para iniciar el chat -

+

Select a dataroom to start chatting

); } @@ -115,9 +127,9 @@ export function ChatTab({ selectedTema }: ChatTabProps) {

- ¡Hola! Soy tu asistente de IA para el dataroom{" "} - {selectedTema}. Puedes hacerme preguntas - sobre los documentos almacenados aquí. + Hi! I’m your AI assistant for dataroom{" "} + {selectedTema}. Ask me anything about the + stored documents.

@@ -206,11 +218,11 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
- Generando reporte de auditoría... + Generating audit report…
); @@ -218,7 +230,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
@@ -229,12 +241,12 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
- Error generando reporte de auditoría + Failed to generate audit report

@@ -251,11 +263,11 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (

- Generando análisis histórico... + Generating performance analysis…
); @@ -263,7 +275,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
@@ -274,12 +286,12 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
- Error generando análisis histórico + Failed to generate performance analysis

@@ -296,11 +308,11 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (

- Searching the web... + Searching the web…
); @@ -308,7 +320,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
@@ -319,12 +331,12 @@ export function ChatTab({ selectedTema }: ChatTabProps) { return (
- Error searching the web + Failed to search the web

@@ -341,8 +353,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { })}

))} - {status === "streaming" && } - {status === "loading" && } + {shouldShowGlobalLoader && }
@@ -363,7 +374,7 @@ export function ChatTab({ selectedTema }: ChatTabProps) { setInput(e.target.value)} value={input} - placeholder={`Pregunta algo sobre ${selectedTema}...`} + placeholder={`Ask something about ${selectedTema}...`} disabled={status === "streaming" || status === "loading"} className="min-h-[60px] resize-none border-0 focus:ring-0 transition-all duration-200 text-base px-4 py-3 bg-white rounded-xl" /> diff --git a/frontend/src/components/DashboardTab.tsx b/frontend/src/components/DashboardTab.tsx index 38075eb..b2858a7 100644 --- a/frontend/src/components/DashboardTab.tsx +++ b/frontend/src/components/DashboardTab.tsx @@ -59,9 +59,8 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { const info = await api.getDataroomInfo(selectedTema); setDataroomInfo(info); } catch (err) { - const errorMessage = - err instanceof Error ? err.message : "Error desconocido"; - setError(`Error cargando información: ${errorMessage}`); + const errorMessage = err instanceof Error ? err.message : "Unknown error"; + setError(`Unable to load dataroom info: ${errorMessage}`); console.error("Error fetching dataroom info:", err); } finally { setLoading(false); @@ -70,7 +69,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { const formatFileTypes = (fileTypes: Record) => { const entries = Object.entries(fileTypes); - if (entries.length === 0) return "Sin archivos"; + if (entries.length === 0) return "No files"; return entries .sort(([, a], [, b]) => b - a) // Sort by count descending @@ -90,9 +89,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { return (
-

- Selecciona un dataroom para ver las métricas -

+

Select a dataroom to view its metrics

); } @@ -101,7 +98,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { return (
-

Cargando métricas...

+

Loading metrics…

); } @@ -124,24 +121,14 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { return (
-

- No se pudo cargar la información del dataroom -

+

Unable to load dataroom information

); } return (
-
-

- Métricas del Dataroom: {selectedTema} -

-

- Vista general del estado y actividad del dataroom -

-
- +

Metrics

{/* Files Count Card */}
@@ -150,7 +137,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) {
-

Archivos

+

Files

{dataroomInfo.file_count}

@@ -168,9 +155,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) {
-

- Almacenamiento -

+

Storage

{dataroomInfo.total_size_mb.toFixed(1)} MB

@@ -188,14 +173,14 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) {
-

Vectores

+

Vectors

{dataroomInfo.vector_count ?? 0}

{dataroomInfo.collection_exists - ? "Vectores indexados" - : "Sin vectores"} + ? "Indexed vectors" + : "No vectors"}

@@ -208,10 +193,10 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) {
-

Estado

+

Status

- {dataroomInfo.collection_exists ? "Activo" : "Inactivo"} + {dataroomInfo.collection_exists ? "Active" : "Inactive"}

{dataroomInfo.collection_exists ? ( @@ -222,14 +207,13 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { {dataroomInfo.collection_info ? (

{dataroomInfo.collection_info.indexed_vectors_count}/ - {dataroomInfo.collection_info.vectors_count} vectores - indexados + {dataroomInfo.collection_info.vectors_count} indexed vectors

) : (

{dataroomInfo.collection_exists - ? "Colección sin datos" - : "Sin colección"} + ? "Collection has no data" + : "No collection"}

)}
@@ -241,7 +225,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) { {dataroomInfo.recent_files.length > 0 && (

- Archivos Recientes + Recent Files

@@ -258,7 +242,7 @@ export function DashboardTab({ selectedTema }: DashboardTabProps) {

{new Date(file.last_modified).toLocaleDateString( - "es-ES", + "en-US", { year: "numeric", month: "short", diff --git a/frontend/src/components/DataroomView.tsx b/frontend/src/components/DataroomView.tsx index df73bd7..3fe0b57 100644 --- a/frontend/src/components/DataroomView.tsx +++ b/frontend/src/components/DataroomView.tsx @@ -87,14 +87,12 @@ export function DataroomView({ onProcessingChange }: DataroomViewProps = {}) {

- {selectedTema - ? `Dataroom: ${selectedTema}` - : "Selecciona un dataroom"} + {selectedTema ? `Dataroom: ${selectedTema}` : "Select a dataroom"}

{selectedTema - ? "Gestiona archivos, consulta métricas y chatea con IA sobre el contenido" - : "Selecciona un dataroom de la barra lateral para comenzar"} + ? "Manage files, review metrics, and chat with AI about the content." + : "Pick a dataroom from the sidebar to get started."}

diff --git a/frontend/src/components/DeleteConfirmDialog.tsx b/frontend/src/components/DeleteConfirmDialog.tsx index 3a03f4a..dbc7bc4 100644 --- a/frontend/src/components/DeleteConfirmDialog.tsx +++ b/frontend/src/components/DeleteConfirmDialog.tsx @@ -1,4 +1,4 @@ -import { Button } from '@/components/ui/button' +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -6,17 +6,17 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from '@/components/ui/dialog' -import { Trash2, AlertTriangle } from 'lucide-react' +} from "@/components/ui/dialog"; +import { Trash2, AlertTriangle } from "lucide-react"; interface DeleteConfirmDialogProps { - open: boolean - onOpenChange: (open: boolean) => void - onConfirm: () => void - title: string - description: string - fileList?: string[] - loading?: boolean + open: boolean; + onOpenChange: (open: boolean) => void; + onConfirm: () => void; + title: string; + description: string; + fileList?: string[]; + loading?: boolean; } export function DeleteConfirmDialog({ @@ -26,7 +26,7 @@ export function DeleteConfirmDialog({ title, description, fileList, - loading = false + loading = false, }: DeleteConfirmDialogProps) { return ( @@ -41,7 +41,7 @@ export function DeleteConfirmDialog({ {fileList && fileList.length > 0 && (
-

Archivos a eliminar:

+

Files to delete:

    {fileList.map((filename, index) => (
  • @@ -59,17 +59,13 @@ export function DeleteConfirmDialog({ onClick={() => onOpenChange(false)} disabled={loading} > - Cancelar + Cancel -
- ) -} \ No newline at end of file + ); +} diff --git a/frontend/src/components/FilesTab.tsx b/frontend/src/components/FilesTab.tsx index 6467b75..f1f51f7 100644 --- a/frontend/src/components/FilesTab.tsx +++ b/frontend/src/components/FilesTab.tsx @@ -60,7 +60,7 @@ export function FilesTab({ const [deleting, setDeleting] = useState(false); const [downloading, setDownloading] = useState(false); - // Estados para el modal de preview de PDF + // PDF preview modal state const [previewModalOpen, setPreviewModalOpen] = useState(false); const [previewFileUrl, setPreviewFileUrl] = useState(null); const [previewFileName, setPreviewFileName] = useState(""); @@ -69,12 +69,12 @@ export function FilesTab({ ); const [loadingPreview, setLoadingPreview] = useState(false); - // Estados para el modal de chunks + // Chunk viewer modal state const [chunkViewerOpen, setChunkViewerOpen] = useState(false); const [chunkFileName, setChunkFileName] = useState(""); const [chunkFileTema, setChunkFileTema] = useState(""); - // Estados para chunking + // LandingAI chunking state const [chunkingConfigOpen, setChunkingConfigOpen] = useState(false); const [chunkingFileName, setChunkingFileName] = useState(""); const [chunkingFileTema, setChunkingFileTema] = useState(""); @@ -123,10 +123,10 @@ export function FilesTab({ setDeleting(true); if (fileToDelete) { - // Eliminar archivo individual + // Delete single file await api.deleteFile(fileToDelete, selectedTema || undefined); } else { - // Eliminar archivos seleccionados + // Delete selected files const filesToDelete = Array.from(selectedFiles); await api.deleteFiles(filesToDelete, selectedTema || undefined); clearSelection(); @@ -159,9 +159,7 @@ export function FilesTab({ try { setDownloading(true); const filesToDownload = Array.from(selectedFiles); - const zipName = selectedTema - ? `${selectedTema}_archivos` - : "archivos_seleccionados"; + const zipName = selectedTema ? `${selectedTema}_files` : "selected_files"; await api.downloadMultipleFiles( filesToDownload, selectedTema || undefined, @@ -234,7 +232,7 @@ export function FilesTab({ } }; - // Filtrar archivos por término de búsqueda + // Filter files by search term const filteredFiles = files.filter((file) => file.name.toLowerCase().includes(searchTerm.toLowerCase()), ); @@ -250,7 +248,7 @@ export function FilesTab({ }; const formatDate = (dateString: string): string => { - return new Date(dateString).toLocaleDateString("es-ES", { + return new Date(dateString).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", @@ -262,15 +260,15 @@ export function FilesTab({ const getDeleteDialogProps = () => { if (fileToDelete) { return { - title: "Eliminar archivo", - message: `¿Estás seguro de que deseas eliminar el archivo "${fileToDelete}"?`, + title: "Delete file", + message: `Are you sure you want to delete "${fileToDelete}"?`, fileList: [fileToDelete], }; } else { const filesToDelete = Array.from(selectedFiles); return { - title: "Eliminar archivos seleccionados", - message: `¿Estás seguro de que deseas eliminar ${filesToDelete.length} archivo${filesToDelete.length > 1 ? "s" : ""}?`, + title: "Delete selected files", + message: `Are you sure you want to delete ${filesToDelete.length} file${filesToDelete.length > 1 ? "s" : ""}?`, fileList: filesToDelete, }; } @@ -280,9 +278,7 @@ export function FilesTab({ return (
-

- Selecciona un dataroom para ver sus archivos -

+

Select a dataroom to view its files

); } @@ -294,7 +290,7 @@ export function FilesTab({
- Procesando archivos con LandingAI... + Processing files with LandingAI…
@@ -305,7 +301,7 @@ export function FilesTab({
setSearchTerm(e.target.value)} className="pl-10" @@ -324,7 +320,7 @@ export function FilesTab({ className="gap-2" > - Descargar ({selectedFiles.size}) + Download ({selectedFiles.size}) )} @@ -345,7 +341,7 @@ export function FilesTab({ className="gap-2" > - Subir archivo + Upload files
@@ -355,17 +351,17 @@ export function FilesTab({
{loading ? (
-

Cargando archivos...

+

Loading files…

) : filteredFiles.length === 0 ? (

{!selectedTema - ? "Selecciona un dataroom para ver sus archivos" + ? "Select a dataroom to view its files" : searchTerm - ? "No se encontraron archivos" - : "No hay archivos en este dataroom"} + ? "No files match your search" + : "This dataroom has no files yet"}

) : ( @@ -387,10 +383,10 @@ export function FilesTab({ }} /> - Archivo - Tamaño - Modificado - Acciones + File + Size + Modified + Actions @@ -418,7 +414,7 @@ export function FilesTab({ onClick={() => handlePreviewFile(file.name)} disabled={loadingPreview} className="h-8 w-8 p-0" - title="Vista previa" + title="Preview" > @@ -427,7 +423,7 @@ export function FilesTab({ size="sm" onClick={() => handleViewChunks(file.name)} className="h-8 w-8 p-0" - title="Ver chunks" + title="View chunks" > @@ -436,7 +432,7 @@ export function FilesTab({ size="sm" onClick={() => handleStartChunking(file.name)} className="h-8 w-8 p-0" - title="Procesar con LandingAI" + title="Process with LandingAI" > @@ -446,7 +442,7 @@ export function FilesTab({ onClick={() => handleDownloadFile(file.name)} disabled={downloading} className="h-8 w-8 p-0" - title="Descargar" + title="Download" > @@ -456,7 +452,7 @@ export function FilesTab({ onClick={() => handleDeleteFile(file.name)} disabled={deleting} className="h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50" - title="Eliminar" + title="Delete" > @@ -503,7 +499,7 @@ export function FilesTab({ tema={chunkFileTema} /> - {/* Modal de configuración de chunking con LandingAI */} + {/* LandingAI chunking config modal */} setChunkingConfigOpen(false)} diff --git a/frontend/src/components/PDFPreviewModal.tsx b/frontend/src/components/PDFPreviewModal.tsx index 2002a5d..ed8e181 100644 --- a/frontend/src/components/PDFPreviewModal.tsx +++ b/frontend/src/components/PDFPreviewModal.tsx @@ -1,25 +1,20 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, - DialogDescription -} from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' -import { - Download, - Loader2, - FileText, - ExternalLink -} from 'lucide-react' + DialogDescription, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Download, Loader2, FileText, ExternalLink } from "lucide-react"; interface PDFPreviewModalProps { - open: boolean - onOpenChange: (open: boolean) => void - fileUrl: string | null - fileName: string - onDownload?: () => void + open: boolean; + onOpenChange: (open: boolean) => void; + fileUrl: string | null; + fileName: string; + onDownload?: () => void; } export function PDFPreviewModal({ @@ -27,45 +22,40 @@ export function PDFPreviewModal({ onOpenChange, fileUrl, fileName, - onDownload + onDownload, }: PDFPreviewModalProps) { - // Estado para manejar el loading del iframe - const [loading, setLoading] = useState(true) + // Track iframe loading state + const [loading, setLoading] = useState(true); - // Efecto para manejar el timeout del loading + // Hide loading if iframe never fires onLoad useEffect(() => { if (open && fileUrl) { - setLoading(true) + setLoading(true); - // Timeout para ocultar loading automáticamente después de 3 segundos - // Algunos iframes no disparan onLoad correctamente const timeout = setTimeout(() => { - setLoading(false) - }, 3000) + setLoading(false); + }, 3000); - return () => clearTimeout(timeout) + return () => clearTimeout(timeout); } - }, [open, fileUrl]) + }, [open, fileUrl]); - // Manejar cuando el iframe termina de cargar const handleIframeLoad = () => { - setLoading(false) - } + setLoading(false); + }; - // Abrir PDF en nueva pestaña const openInNewTab = () => { if (fileUrl) { - window.open(fileUrl, '_blank') + window.open(fileUrl, "_blank"); } - } + }; - // Reiniciar loading cuando cambia el archivo const handleOpenChange = (open: boolean) => { if (open) { - setLoading(true) + setLoading(true); } - onOpenChange(open) - } + onOpenChange(open); + }; return ( @@ -75,81 +65,68 @@ export function PDFPreviewModal({ {fileName} - - Vista previa del documento PDF - + PDF preview - {/* Barra de controles */} + {/* Controls */}
- {/* Botón de descarga */} + {/* Download button */} {onDownload && ( )}
- {/* Área de visualización del PDF con iframe */} -
+ {/* PDF iframe */} +
{!fileUrl ? (
-

No se ha proporcionado un archivo para previsualizar

+

No file available for preview

) : ( <> - {/* Indicador de carga */} + {/* Loading state */} {loading && (
-

Cargando PDF...

+

Loading PDF…

)} - {/* - Iframe para mostrar el PDF - El navegador maneja toda la visualización, zoom, scroll, etc. - Esto muestra el PDF exactamente como se vería si lo abrieras directamente - */}