fix(webui): stabilize streaming output and settings i18n

This commit is contained in:
Xubin Ren 2026-05-31 20:52:56 +08:00
parent 31722120b7
commit 34386fe676
13 changed files with 1164 additions and 1048 deletions

View File

@ -137,10 +137,6 @@ function currentActivityClusterIndices(units: DisplayUnit[]): Set<number> {
if (!markedCurrentActivity) { if (!markedCurrentActivity) {
indices.add(i); indices.add(i);
markedCurrentActivity = true; markedCurrentActivity = true;
continue;
}
if (activityHasLiveFileEdit(unit)) {
indices.add(i);
} }
continue; continue;
} }
@ -150,13 +146,6 @@ function currentActivityClusterIndices(units: DisplayUnit[]): Set<number> {
return indices; return indices;
} }
function activityHasLiveFileEdit(unit: Extract<DisplayUnit, { type: "activity" }>): boolean {
return unit.messages.some((message) => (
message.kind === "trace"
&& message.fileEdits?.some((edit) => edit.status === "editing" || edit.pending || !edit.path)
));
}
function unitKey(unit: DisplayUnit, index: number): string { function unitKey(unit: DisplayUnit, index: number): string {
if (unit.type === "activity") { if (unit.type === "activity") {
const anchor = unit.messages[0]?.id; const anchor = unit.messages[0]?.id;

View File

@ -58,11 +58,10 @@ function findStreamingAssistantIndex(
/** /**
* Append a reasoning chunk to the last open reasoning stream in ``prev``. * Append a reasoning chunk to the last open reasoning stream in ``prev``.
* *
* Lookup rule: prefer the most recent assistant turn in the active UI tail. * Lookup rule: reasoning can only extend the current reasoning placeholder.
* Most providers emit reasoning before answer text, but some only expose * Once ordinary answer text has appeared, the next reasoning chunk starts a
* ``reasoning_content`` after the answer stream completes. In that post-hoc * fresh Thought block so streamed output stays in arrival order:
* case the reasoning still belongs to the same assistant turn and must render * Thought -> answer -> Thought -> answer.
* above the answer, not as a new row below it.
*/ */
function attachReasoningChunk( function attachReasoningChunk(
prev: UIMessage[], prev: UIMessage[],
@ -83,10 +82,10 @@ function attachReasoningChunk(
if (candidate.role !== "assistant") continue; if (candidate.role !== "assistant") continue;
const activitySegmentId = candidate.activitySegmentId ?? segments?.ensure(); const activitySegmentId = candidate.activitySegmentId ?? segments?.ensure();
const hasAnswer = candidate.content.length > 0; const hasAnswer = candidate.content.length > 0;
if (hasAnswer) break;
if ( if (
candidate.reasoningStreaming candidate.reasoningStreaming
|| candidate.reasoning !== undefined || candidate.reasoning !== undefined
|| hasAnswer
|| candidate.isStreaming || candidate.isStreaming
) { ) {
const merged: UIMessage = { const merged: UIMessage = {
@ -97,15 +96,6 @@ function attachReasoningChunk(
}; };
return [...prev.slice(0, i), merged, ...prev.slice(i + 1)]; return [...prev.slice(0, i), merged, ...prev.slice(i + 1)];
} }
if (!hasAnswer && candidate.isStreaming) {
const merged: UIMessage = {
...candidate,
reasoning: chunk,
reasoningStreaming: true,
...(activitySegmentId ? { activitySegmentId } : {}),
};
return [...prev.slice(0, i), merged, ...prev.slice(i + 1)];
}
break; break;
} }
const activitySegmentId = segments?.ensure(); const activitySegmentId = segments?.ensure();
@ -293,38 +283,6 @@ function stripCoveredFileEditToolHints(message: UIMessage, edits: UIFileEdit[]):
}; };
} }
function demoteInterruptedAssistantToActivity(
prev: UIMessage[],
segmentId: string,
): UIMessage[] {
for (let i = prev.length - 1; i >= 0; i -= 1) {
const message = prev[i];
if (message.role === "user") break;
if (
message.role !== "assistant"
|| message.kind === "trace"
|| !message.isStreaming
|| !message.content.trim()
|| message.media?.length
) {
continue;
}
const reasoning = [message.reasoning, message.content]
.filter((part): part is string => typeof part === "string" && part.trim().length > 0)
.join("\n\n");
const demoted: UIMessage = {
...message,
content: "",
reasoning,
reasoningStreaming: false,
isStreaming: false,
activitySegmentId: message.activitySegmentId ?? segmentId,
};
return replaceMessageAt(prev, i, demoted);
}
return prev;
}
function normalizeFileEdit(edit: UIFileEdit): UIFileEdit | null { function normalizeFileEdit(edit: UIFileEdit): UIFileEdit | null {
if (!edit || !edit.tool || (!edit.path && !edit.pending)) return null; if (!edit || !edit.tool || (!edit.path && !edit.pending)) return null;
const inferredStatus = const inferredStatus =
@ -511,6 +469,7 @@ export function useNanobotStream(
if (closedStreamId) closedAssistantStreamIdsRef.current.add(closedStreamId); if (closedStreamId) closedAssistantStreamIdsRef.current.add(closedStreamId);
buffer.current = null; buffer.current = null;
activeAssistantRef.current = null; activeAssistantRef.current = null;
return !!closedStreamId;
}, []); }, []);
const resolveActiveAssistantIndex = useCallback((prev: UIMessage[]): number | null => { const resolveActiveAssistantIndex = useCallback((prev: UIMessage[]): number | null => {
@ -589,15 +548,18 @@ export function useNanobotStream(
text += events[i].text; text += events[i].text;
i += 1; i += 1;
} }
next = kind === "delta" if (kind === "delta") {
? appendAnswerChunk(next, text) next = appendAnswerChunk(next, text);
: attachReasoningChunk(next, text, { } else {
ensure: ensureActivitySegmentId, if (closeActiveAssistantStream()) clearActivitySegment();
}); next = attachReasoningChunk(next, text, {
ensure: ensureActivitySegmentId,
});
}
} }
return next; return next;
}, },
[appendAnswerChunk, ensureActivitySegmentId], [appendAnswerChunk, clearActivitySegment, closeActiveAssistantStream, ensureActivitySegmentId],
); );
const flushPendingStreamEvents = useCallback((options?: { const flushPendingStreamEvents = useCallback((options?: {
@ -735,7 +697,13 @@ export function useNanobotStream(
return; return;
} }
flushPendingStreamEvents(); const shouldCloseAnswerBeforeEvent =
ev.event === "file_edit"
|| (
ev.event === "message"
&& (ev.kind === "tool_hint" || ev.kind === "progress")
);
flushPendingStreamEvents({ closeAnswerSegment: shouldCloseAnswerBeforeEvent });
if (ev.event === "reasoning_end") { if (ev.event === "reasoning_end") {
if (suppressStreamUntilTurnEndRef.current) return; if (suppressStreamUntilTurnEndRef.current) return;
@ -812,7 +780,7 @@ export function useNanobotStream(
const structuredEvents = normalizeToolProgressEvents(ev.tool_events); const structuredEvents = normalizeToolProgressEvents(ev.tool_events);
setMessages((prev) => { setMessages((prev) => {
const segmentId = ensureActivitySegmentId(); const segmentId = ensureActivitySegmentId();
const base = demoteInterruptedAssistantToActivity(prev, segmentId); const base = prev;
const visibleStructuredEvents = filterCoveredFileEditToolEvents(base, structuredEvents); const visibleStructuredEvents = filterCoveredFileEditToolEvents(base, structuredEvents);
const structuredLines = toolTraceLinesFromEvents(visibleStructuredEvents); const structuredLines = toolTraceLinesFromEvents(visibleStructuredEvents);
const lines = structuredLines.length > 0 const lines = structuredLines.length > 0
@ -914,7 +882,7 @@ export function useNanobotStream(
} }
setMessages((prev) => { setMessages((prev) => {
let segmentId = eventSegmentId; let segmentId = eventSegmentId;
const base = segmentId ? demoteInterruptedAssistantToActivity(prev, segmentId) : prev; const base = prev;
const targetIndex = findFileEditTraceIndex(base, segmentId, normalized); const targetIndex = findFileEditTraceIndex(base, segmentId, normalized);
if (targetIndex !== null) { if (targetIndex !== null) {
const target = base[targetIndex]; const target = base[targetIndex];

View File

@ -59,43 +59,43 @@
"settings": { "settings": {
"backToChat": "Volver al chat", "backToChat": "Volver al chat",
"sidebar": { "sidebar": {
"title": "Configuración", "title": "Ajustes",
"ariaLabel": "Secciones de configuración" "ariaLabel": "Secciones de ajustes"
}, },
"nav": { "nav": {
"general": "General", "general": "General",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "Resumen",
"appearance": "Appearance", "appearance": "Apariencia",
"models": "Models", "models": "Modelos",
"providers": "Providers", "providers": "Proveedores",
"image": "Image", "image": "Imagen",
"browser": "Web", "browser": "Internet",
"runtime": "Sistema", "runtime": "Sistema",
"advanced": "Security", "advanced": "Seguridad",
"cliApps": "Apps CLI", "cliApps": "Apps CLI",
"mcp": "MCP", "mcp": "MCP",
"apps": "Apps" "apps": "Aplicaciones"
}, },
"sections": { "sections": {
"interface": "Interfaz", "interface": "Interfaz",
"ai": "IA", "ai": "AI",
"system": "Sistema", "system": "Sistema",
"status": "Status", "status": "Estado",
"localPreferences": "Local preferences", "localPreferences": "Preferencias locales",
"presets": "Presets", "presets": "Preajustes",
"imageGeneration": "Generación de imágenes", "imageGeneration": "Generación de imágenes",
"imageDefaults": "Valores predeterminados", "imageDefaults": "Valores predeterminados",
"webSearch": "Web search", "webSearch": "Búsqueda web",
"webBehavior": "Behavior", "webBehavior": "Comportamiento",
"identity": "Identity", "identity": "Identidad",
"webuiSafety": "Web safety", "webuiSafety": "Seguridad de WebUI",
"capabilities": "Capacidades", "capabilities": "Capacidades",
"cliApps": "Apps CLI", "cliApps": "Aplicaciones CLI",
"mcp": "Servicios MCP", "mcp": "Servicios MCP",
"apps": "Apps", "apps": "Aplicaciones",
"nativeHost": "App", "nativeHost": "Host nativo",
"hostSafety": "App safety" "hostSafety": "Seguridad de la app"
}, },
"rows": { "rows": {
"theme": "Tema", "theme": "Tema",
@ -104,118 +104,118 @@
"model": "Modelo", "model": "Modelo",
"restart": "Reiniciar nanobot", "restart": "Reiniciar nanobot",
"configPath": "Ruta de configuración", "configPath": "Ruta de configuración",
"activePreset": "Active preset", "activePreset": "Preajuste activo",
"gateway": "Gateway", "gateway": "Pasarela",
"restartState": "Restart state", "restartState": "Estado de reinicio",
"pendingChanges": "Cambios pendientes", "pendingChanges": "Cambios pendientes",
"selectedPreset": "Selected preset", "selectedPreset": "Preajuste seleccionado",
"presetModel": "Preset model", "presetModel": "Modelo del preajuste",
"density": "Density", "density": "Densidad",
"activityMode": "Activity detail", "activityMode": "Detalle de actividad",
"codeWrap": "Code wrapping", "codeWrap": "Ajuste de código",
"maxResults": "Max results", "maxResults": "Resultados máximos",
"timeout": "Timeout", "timeout": "Tiempo de espera",
"jinaReader": "Jina reader", "jinaReader": "Lector Jina",
"imageGeneration": "Generación de imágenes", "imageGeneration": "Generación de imágenes",
"imageProvider": "Proveedor de imágenes", "imageProvider": "Proveedor de imágenes",
"imageProviderStatus": "Estado del proveedor", "imageProviderStatus": "Estado del proveedor",
"imageProviderBase": "Base del proveedor", "imageProviderBase": "Base del proveedor",
"imageModel": "Modelo de imagen", "imageModel": "Modelo de imagen",
"defaultAspectRatio": "Relación predeterminada", "defaultAspectRatio": "Proporción predeterminada",
"defaultImageSize": "Tamaño predeterminado", "defaultImageSize": "Tamaño predeterminado",
"maxImagesPerTurn": "Máximo de imágenes por turno", "maxImagesPerTurn": "Máx. imágenes por turno",
"imageSaveDir": "Directorio de guardado", "imageSaveDir": "Directorio de guardado",
"botName": "Bot name", "botName": "Nombre del bot",
"botIcon": "Bot icon", "botIcon": "Icono del bot",
"timezone": "Timezone", "timezone": "Zona horaria",
"workspacePath": "Workspace predeterminado", "workspacePath": "Workspace predeterminado",
"localServiceAccess": "Local services", "localServiceAccess": "Servicios locales",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "Acceso predeterminado",
"currentModel": "Configuración actual", "currentModel": "Configuración actual",
"brandLogos": "Logotipos de marca", "brandLogos": "Logos de marca",
"cliAppsCatalog": "Catálogo de apps CLI", "cliAppsCatalog": "Catálogo",
"cliAppsFilter": "Filtro de apps CLI", "cliAppsFilter": "Filtro",
"engine": "Motor", "engine": "Motor",
"logs": "Registros", "logs": "Registros",
"diagnostics": "Diagnóstico", "diagnostics": "Diagnóstico",
"contextWindow": "Context window" "contextWindow": "Ventana de contexto"
}, },
"help": { "help": {
"theme": "Cambia entre apariencia clara y oscura.", "theme": "Cambia entre apariencia clara y oscura.",
"language": "Elige el idioma usado por la WebUI.", "language": "Elige el idioma usado por WebUI.",
"provider": "Selecciona el proveedor para nuevas solicitudes de modelo.", "provider": "Selecciona el proveedor para nuevas solicitudes de modelo.",
"model": "Define el nombre del modelo predeterminado que usa nanobot.", "model": "Define el nombre de modelo predeterminado de nanobot.",
"configPath": "El archivo de configuración que usa actualmente el gateway.", "configPath": "Archivo de configuración que usa actualmente el gateway.",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "Los preajustes con nombre son de solo lectura aquí; edítalos en config.json.",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Cambia a Default para editar modelo y proveedor desde WebUI.",
"density": "Stored only in this browser.", "density": "Solo se guarda en este navegador.",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "Elige cuánto detalle de actividad del agente se muestra por defecto.",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "Mantiene legibles las líneas largas de código en pantallas pequeñas.",
"maxResults": "Results returned by each web_search call.", "maxResults": "Resultados devueltos por cada llamada web_search.",
"timeout": "Seconds before a search provider request times out.", "timeout": "Segundos antes de que una solicitud de búsqueda expire.",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "Usa Jina Reader para web_fetch cuando esté disponible.",
"imageGeneration": "Expone generate_image en los chats cuando hay un proveedor de imágenes configurado disponible.", "imageGeneration": "Expone generate_image en chats cuando hay un proveedor de imagen configurado.",
"imageProvider": "Elige el proveedor del registro que usará generate_image.", "imageProvider": "Elige el proveedor registrado usado por generate_image.",
"imageProviderStatus": "La generación de imágenes reutiliza las credenciales de Proveedores.", "imageProviderStatus": "La generación de imágenes reutiliza credenciales de Proveedores.",
"imageModel": "Nombre del modelo enviado al proveedor de imágenes seleccionado.", "imageModel": "Nombre del modelo enviado al proveedor de imágenes seleccionado.",
"defaultAspectRatio": "Se usa cuando el prompt no elige una relación de aspecto.", "defaultAspectRatio": "Se usa cuando el prompt no elige una proporción.",
"defaultImageSize": "Sugerencia de tamaño enviada a los proveedores que la admiten.", "defaultImageSize": "Pista de tamaño enviada a proveedores compatibles.",
"maxImagesPerTurn": "Límite superior para una solicitud generate_image.", "maxImagesPerTurn": "Límite superior para una solicitud generate_image.",
"botName": "Se muestra donde nanobot usa un nombre visible.", "botName": "Se muestra donde nanobot usa un nombre visible.",
"botIcon": "Emoji o texto corto mostrado junto al nombre del bot.", "botIcon": "Emoji o texto corto junto al nombre del bot.",
"timezone": "Se usa para programaciones y respuestas sensibles al tiempo.", "timezone": "Se usa para horarios y respuestas con conciencia temporal.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Permite que comandos shell con Full Access alcancen servicios localhost.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "Usado por chats web sin permiso específico de proyecto.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "Las capturas web siempre protegen servicios locales, privados y metadata. La seguridad de canales core se gestiona en config.json.",
"currentModel": "Elige la configuración de modelo que nanobot usará para las próximas respuestas.", "currentModel": "Se usa para nuevas respuestas.",
"selectedModelProvider": "Lo define el modelo seleccionado.", "selectedModelProvider": "Definido por el modelo seleccionado.",
"selectedModelValue": "Lo define el modelo seleccionado.", "selectedModelValue": "Definido por el modelo seleccionado.",
"brandLogos": "Los logotipos se cargan desde los dominios de las marcas con una reserva de icono local.", "brandLogos": "Muestra logos de proveedores de terceros y CLI en Ajustes.",
"cliAppsCatalog": "Explora CLIs de apps que nanobot puede ejecutar localmente.", "cliAppsCatalog": "Instala solo adaptadores CLI de apps que nanobot puede ejecutar localmente; las apps nativas no se modifican.",
"cliAppsFilter": "Busca por app, categoría o capacidad.", "cliAppsFilter": "Busca por app, categoría o capacidad.",
"logs": "Abre la carpeta de registros del motor de escritorio.", "logs": "Abre la carpeta de registros del motor nativo.",
"diagnostics": "Exporta un pequeño informe de runtime para soporte.", "diagnostics": "Exporta un pequeño informe de runtime para soporte.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Permite que comandos shell con Full Access alcancen servicios en este Mac.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "Usado por chats nativos sin permiso específico de proyecto.",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "Elige el presupuesto de contexto predeterminado para esta configuración de modelo."
}, },
"values": { "values": {
"light": "Claro", "light": "Claro",
"dark": "Oscuro", "dark": "Oscuro",
"notAvailable": "No disponible", "notAvailable": "No disponible",
"enabled": "Enabled", "enabled": "Activado",
"disabled": "Disabled", "disabled": "Desactivado",
"restartPending": "Reinicio pendiente", "restartPending": "Reinicio pendiente",
"ready": "Listo", "ready": "Listo",
"comfortable": "Comfortable", "comfortable": "Cómodo",
"compact": "Compact", "compact": "Compacto",
"auto": "Auto", "auto": "Automático",
"expanded": "Expanded", "expanded": "Expandido",
"on": "On", "on": "Activado",
"off": "Off", "off": "Desactivado",
"defaultPermission": "Default Permission", "defaultPermission": "Permiso predeterminado",
"fullAccess": "Full Access", "fullAccess": "Acceso completo",
"configured": "Configured", "configured": "Configurado",
"notConfigured": "Not configured", "notConfigured": "Sin configurar",
"pending": "Pendiente", "pending": "Pendiente",
"restartingEngine": "Reiniciando" "restartingEngine": "Reiniciando"
}, },
"status": { "status": {
"loading": "Cargando configuración...", "loading": "Cargando ajustes...",
"loadError": "No se pudo cargar la configuración", "loadError": "No se pudieron cargar los ajustes",
"unsaved": "Hay cambios sin guardar.", "unsaved": "Cambios sin guardar.",
"upToDate": "Actualizado.", "upToDate": "Actualizado.",
"savedRestart": "Guardado. Reinicia nanobot para aplicar.", "savedRestart": "Guardado. Reinicia nanobot para aplicar.",
"restartAfterSaving": "Guarda los cambios y reinicia cuando estés listo.", "restartAfterSaving": "Guarda los cambios y reinicia cuando puedas.",
"savedRestartApply": "Guardado. Reinicia cuando estés listo.", "savedRestartApply": "Guardado. Reinicia cuando puedas.",
"imageProviderRestart": "Cambios del proveedor de imágenes guardados. Reinicia cuando estés listo.", "imageProviderRestart": "Cambios del proveedor de imagen guardados. Reinicia cuando puedas.",
"hostRestartAfterSaving": "Guarda los cambios y nanobot reiniciará su motor.", "hostRestartAfterSaving": "Al guardar, nanobot reiniciará su motor.",
"hostRestartPending": "Guardado. Reiniciando el motor cuando esté listo.", "hostRestartPending": "Guardado. El motor se reiniciará cuando esté listo.",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "Las acciones del host solo están disponibles en la app nativa.",
"logsOpened": "Opened logs folder.", "logsOpened": "Carpeta de registros abierta.",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "No se pudo abrir la carpeta de registros.",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "Diagnóstico exportado a {{path}}.",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "No se pudo exportar el diagnóstico."
}, },
"actions": { "actions": {
"save": "Guardar", "save": "Guardar",
@ -224,8 +224,8 @@
"cancel": "Cancelar", "cancel": "Cancelar",
"open": "Abrir", "open": "Abrir",
"export": "Exportar", "export": "Exportar",
"opening": "Opening...", "opening": "Abriendo...",
"exporting": "Exporting..." "exporting": "Exportando..."
}, },
"byok": { "byok": {
"description": "Usa tus propias claves de proveedor. Nanobot lee estos valores desde la configuración actual, y solo los proveedores configurados se pueden elegir en General.", "description": "Usa tus propias claves de proveedor. Nanobot lee estos valores desde la configuración actual, y solo los proveedores configurados se pueden elegir en General.",
@ -250,7 +250,7 @@
"tabs": { "tabs": {
"ariaLabel": "Tipo de credencial BYOK", "ariaLabel": "Tipo de credencial BYOK",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "Búsqueda web"
}, },
"webSearch": { "webSearch": {
"provider": "Proveedor de búsqueda", "provider": "Proveedor de búsqueda",
@ -270,44 +270,44 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "Modelo actual",
"providers": "Providers", "providers": "Proveedores",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}} configurados",
"totalProviders": "{{count}} available", "totalProviders": "{{count}} disponibles",
"webSearch": "Web search", "webSearch": "Búsqueda web",
"imageGeneration": "Generación de imágenes", "imageGeneration": "Generación de imágenes",
"workspace": "Workspace" "workspace": "Espacio de trabajo"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "Buscar proveedores",
"noMatches": "No providers match this search.", "noMatches": "Ningún proveedor coincide con esta búsqueda.",
"saveProvider": "Guardar proveedor" "saveProvider": "Guardar proveedor"
}, },
"image": { "image": {
"selectProvider": "Seleccionar proveedor", "selectProvider": "Seleccionar proveedor",
"selectAspect": "Seleccionar relación", "selectAspect": "Seleccionar proporción",
"selectSize": "Seleccionar tamaño", "selectSize": "Seleccionar tamaño",
"configureProvider": "Configurar proveedor", "configureProvider": "Configurar proveedor",
"missingCredential": "Configura este proveedor antes de activar la generación de imágenes." "missingCredential": "Configura este proveedor antes de activar la generación de imágenes."
}, },
"models": { "models": {
"selectModel": "Seleccionar modelo", "selectModel": "Seleccionar modelo",
"addConfiguration": "Añadir configuración", "addConfiguration": "Agregar configuración",
"newConfiguration": "Nueva configuración de modelo", "newConfiguration": "Nueva configuración de modelo",
"newConfigurationHelp": "Guarda un proveedor y un modelo como una opción de un clic.", "newConfigurationHelp": "Guarda un proveedor y modelo como opción de un clic.",
"configurationName": "Nombre de configuración", "configurationName": "Nombre de configuración",
"configurationNameHelp": "Cambia el nombre de esta configuración de modelo guardada.", "configurationNameHelp": "Renombra esta configuración de modelo guardada.",
"configurationNamePlaceholder": "Escritura rápida", "configurationNamePlaceholder": "Escritura rápida",
"searchModels": "Buscar o escribir ID de modelo", "searchModels": "Buscar o escribir ID de modelo",
"useCustomModel": "Usar", "useCustomModel": "Usar",
"loadingModels": "Cargando modelos...", "loadingModels": "Cargando modelos...",
"searchCatalog": "Busca en el catálogo del proveedor para elegir un modelo.", "searchCatalog": "Busca el catálogo del proveedor para elegir un modelo.",
"modelsAvailable": "disponibles", "modelsAvailable": "disponibles",
"noModelResults": "No hay modelos coincidentes.", "noModelResults": "No hay modelos coincidentes.",
"loadFailed": "Lista de modelos no disponible.", "loadFailed": "Lista de modelos no disponible.",
"unsupportedModelList": "Escribe manualmente un ID de modelo.", "unsupportedModelList": "Escribe un ID de modelo manualmente.",
"providerNotConfigured": "Configura este proveedor antes de cargar modelos.", "providerNotConfigured": "Configura este proveedor antes de cargar modelos.",
"autoProviderCustomOnly": "El modo de proveedor automático usa ID de modelo personalizados." "autoProviderCustomOnly": "El modo de proveedor automático usa IDs de modelo personalizados."
}, },
"timezone": { "timezone": {
"select": "Seleccionar zona horaria", "select": "Seleccionar zona horaria",
@ -316,7 +316,7 @@
}, },
"cliApps": { "cliApps": {
"allCategories": "Todas las categorías", "allCategories": "Todas las categorías",
"availableCount": "{{count}} apps", "availableCount": "{{count}} aplicaciones",
"installedCount": "{{count}} instaladas", "installedCount": "{{count}} instaladas",
"summary": "{{installed}} de {{total}} CLIs instaladas", "summary": "{{installed}} de {{total}} CLIs instaladas",
"filterAll": "Todas", "filterAll": "Todas",
@ -402,7 +402,7 @@
"thirdPartyBrands": "Los nombres, logotipos y marcas de productos pertenecen a sus respectivos propietarios. Su uso es solo identificativo y no implica respaldo." "thirdPartyBrands": "Los nombres, logotipos y marcas de productos pertenecen a sus respectivos propietarios. Su uso es solo identificativo y no implica respaldo."
}, },
"apps": { "apps": {
"description": "Añade CLI de apps y servicios MCP que nanobot puede usar desde el chat.", "description": "Agrega CLI de apps y servicios MCP que nanobot puede usar desde el chat.",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "Todo", "filterAll": "Todo",
@ -416,17 +416,17 @@
"empty": "Ninguna app coincide con este filtro." "empty": "Ninguna app coincide con este filtro."
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "Autenticación OAuth",
"signIn": "Sign in", "signIn": "Iniciar sesión",
"signingIn": "Signing in...", "signingIn": "Iniciando sesión...",
"signInAgain": "Sign in again", "signInAgain": "Iniciar sesión de nuevo",
"signOut": "Sign out", "signOut": "Cerrar sesión",
"signedInAs": "Signed in as {{account}}", "signedInAs": "Sesión iniciada como {{account}}",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "Inicia sesión desde este dispositivo; no se guarda API key en config.",
"signInRequired": "Sign in required", "signInRequired": "Inicio de sesión requerido",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "Inicia sesión antes de guardar este proveedor OAuth como proveedor activo.",
"signedIn": "Signed in", "signedIn": "Sesión iniciada",
"notSignedIn": "Not signed in" "notSignedIn": "Sin sesión"
} }
}, },
"chat": { "chat": {

View File

@ -57,45 +57,45 @@
"apps": "Apps" "apps": "Apps"
}, },
"settings": { "settings": {
"backToChat": "Retour à la discussion", "backToChat": "Retour au chat",
"sidebar": { "sidebar": {
"title": "Paramètres", "title": "Réglages",
"ariaLabel": "Sections des paramètres" "ariaLabel": "Sections des réglages"
}, },
"nav": { "nav": {
"general": "Général", "general": "Général",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "Aperçu",
"appearance": "Appearance", "appearance": "Apparence",
"models": "Models", "models": "Modèles",
"providers": "Providers", "providers": "Fournisseurs",
"image": "Image", "image": "Images",
"browser": "Web", "browser": "Internet",
"runtime": "Système", "runtime": "Système",
"advanced": "Security", "advanced": "Sécurité",
"cliApps": "Apps CLI", "cliApps": "Apps CLI",
"mcp": "MCP", "mcp": "MCP",
"apps": "Apps" "apps": "Applications"
}, },
"sections": { "sections": {
"interface": "Interface", "interface": "Interface utilisateur",
"ai": "IA", "ai": "AI",
"system": "Système", "system": "Système",
"status": "Status", "status": "État",
"localPreferences": "Local preferences", "localPreferences": "Préférences locales",
"presets": "Presets", "presets": "Préréglages",
"imageGeneration": "Génération d'images", "imageGeneration": "Génération dimages",
"imageDefaults": "Valeurs par défaut", "imageDefaults": "Valeurs par défaut",
"webSearch": "Web search", "webSearch": "Recherche web",
"webBehavior": "Behavior", "webBehavior": "Comportement",
"identity": "Identity", "identity": "Identité",
"webuiSafety": "Web safety", "webuiSafety": "Sécurité WebUI",
"capabilities": "Capacités", "capabilities": "Capacités",
"cliApps": "Apps CLI", "cliApps": "Applications CLI",
"mcp": "Services MCP", "mcp": "Services MCP",
"apps": "Apps", "apps": "Applications",
"nativeHost": "App", "nativeHost": "Hôte natif",
"hostSafety": "App safety" "hostSafety": "Sécurité de lapp"
}, },
"rows": { "rows": {
"theme": "Thème", "theme": "Thème",
@ -103,119 +103,119 @@
"provider": "Fournisseur", "provider": "Fournisseur",
"model": "Modèle", "model": "Modèle",
"restart": "Redémarrer nanobot", "restart": "Redémarrer nanobot",
"configPath": "Chemin de configuration", "configPath": "Chemin de config",
"activePreset": "Active preset", "activePreset": "Préréglage actif",
"gateway": "Gateway", "gateway": "Passerelle",
"restartState": "Restart state", "restartState": "État du redémarrage",
"pendingChanges": "Modifications en attente", "pendingChanges": "Modifications en attente",
"selectedPreset": "Selected preset", "selectedPreset": "Préréglage sélectionné",
"presetModel": "Preset model", "presetModel": "Modèle du préréglage",
"density": "Density", "density": "Densité",
"activityMode": "Activity detail", "activityMode": "Détail dactivité",
"codeWrap": "Code wrapping", "codeWrap": "Retour à la ligne du code",
"maxResults": "Max results", "maxResults": "Résultats max.",
"timeout": "Timeout", "timeout": "Délai dattente",
"jinaReader": "Jina reader", "jinaReader": "Lecteur Jina",
"imageGeneration": "Génération d'images", "imageGeneration": "Génération dimages",
"imageProvider": "Fournisseur d'images", "imageProvider": "Fournisseur dimages",
"imageProviderStatus": "État du fournisseur", "imageProviderStatus": "État du fournisseur",
"imageProviderBase": "Base du fournisseur", "imageProviderBase": "Base du fournisseur",
"imageModel": "Modèle d'image", "imageModel": "Modèle dimage",
"defaultAspectRatio": "Format par défaut", "defaultAspectRatio": "Ratio par défaut",
"defaultImageSize": "Taille par défaut", "defaultImageSize": "Taille par défaut",
"maxImagesPerTurn": "Nombre max. d'images par tour", "maxImagesPerTurn": "Images max. par tour",
"imageSaveDir": "Répertoire de sauvegarde", "imageSaveDir": "Dossier denregistrement",
"botName": "Bot name", "botName": "Nom du bot",
"botIcon": "Bot icon", "botIcon": "Icône du bot",
"timezone": "Timezone", "timezone": "Fuseau horaire",
"workspacePath": "Espace de travail par défaut", "workspacePath": "Espace de travail par défaut",
"localServiceAccess": "Local services", "localServiceAccess": "Services locaux",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "Accès par défaut",
"currentModel": "Configuration actuelle", "currentModel": "Configuration actuelle",
"brandLogos": "Logos de marque", "brandLogos": "Logos de marque",
"cliAppsCatalog": "Catalogue d'apps CLI", "cliAppsCatalog": "Catalogue",
"cliAppsFilter": "Filtre des apps CLI", "cliAppsFilter": "Filtre",
"engine": "Moteur", "engine": "Moteur",
"logs": "Journaux", "logs": "Journaux",
"diagnostics": "Diagnostics", "diagnostics": "Diagnostic",
"contextWindow": "Context window" "contextWindow": "Fenêtre de contexte"
}, },
"help": { "help": {
"theme": "Basculer entre les apparences claire et sombre.", "theme": "Basculer entre lapparence claire et sombre.",
"language": "Choisissez la langue utilisée par le WebUI.", "language": "Choisissez la langue utilisée par WebUI.",
"provider": "Sélectionnez le fournisseur des nouvelles requêtes de modèle.", "provider": "Sélectionnez le fournisseur à utiliser pour les nouvelles requêtes de modèle.",
"model": "Définissez le nom du modèle par défaut utilisé par nanobot.", "model": "Définissez le nom du modèle utilisé par défaut par nanobot.",
"configPath": "Le fichier de configuration actuellement utilisé par la passerelle.", "configPath": "Le fichier de configuration actuellement utilisé par la passerelle.",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "Les préréglages nommés sont en lecture seule ici ; modifiez-les dans config.json.",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Passez à Default pour modifier le modèle et le fournisseur depuis WebUI.",
"density": "Stored only in this browser.", "density": "Enregistré seulement dans ce navigateur.",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "Choisissez le niveau de détail dactivité agent affiché par défaut.",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "Garde les longues lignes de code lisibles sur les petits écrans.",
"maxResults": "Results returned by each web_search call.", "maxResults": "Résultats renvoyés par chaque appel web_search.",
"timeout": "Seconds before a search provider request times out.", "timeout": "Nombre de secondes avant lexpiration dune requête de recherche.",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "Utilise Jina Reader pour web_fetch lorsque disponible.",
"imageGeneration": "Expose generate_image dans les chats lorsquun fournisseur dimages configuré est disponible.", "imageGeneration": "Expose generate_image dans les chats lorsquun fournisseur dimage configuré est disponible.",
"imageProvider": "Choisissez le fournisseur du registre utilisé par generate_image.", "imageProvider": "Choisissez le fournisseur inscrit utilisé par generate_image.",
"imageProviderStatus": "La génération dimages réutilise les identifiants de Fournisseurs.", "imageProviderStatus": "La génération dimages réutilise les identifiants des fournisseurs.",
"imageModel": "Nom du modèle envoyé au fournisseur dimages sélectionné.", "imageModel": "Nom du modèle envoyé au fournisseur dimages sélectionné.",
"defaultAspectRatio": "Utilisé lorsque le prompt ne choisit pas de format.", "defaultAspectRatio": "Utilisé lorsque le prompt ne choisit pas de ratio.",
"defaultImageSize": "Indication de taille envoyée aux fournisseurs qui la prennent en charge.", "defaultImageSize": "Indication de taille envoyée aux fournisseurs compatibles.",
"maxImagesPerTurn": "Limite supérieure pour une requête generate_image.", "maxImagesPerTurn": "Limite supérieure pour une requête generate_image.",
"botName": "Affiché partout où nanobot utilise un nom visible.", "botName": "Affiché où nanobot utilise un nom visible.",
"botIcon": "Emoji ou texte court affiché avec le nom du bot.", "botIcon": "Emoji ou texte court affiché avec le nom du bot.",
"timezone": "Utilisé pour les planifications et les réponses sensibles à lheure.", "timezone": "Utilisé pour les horaires et les réponses tenant compte du temps.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Autorise les commandes shell Full Access à atteindre les services localhost.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "Utilisé par les chats web sans permission propre au projet.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "Les récupérations web protègent toujours les services locaux, privés et de métadonnées. La sécurité des canaux principaux reste gérée dans config.json.",
"currentModel": "Choisissez la configuration de modèle que nanobot utilisera pour les prochaines réponses.", "currentModel": "Utilisée pour les nouvelles réponses.",
"selectedModelProvider": "Défini par le modèle sélectionné.", "selectedModelProvider": "Défini par le modèle sélectionné.",
"selectedModelValue": "Défini par le modèle sélectionné.", "selectedModelValue": "Défini par le modèle sélectionné.",
"brandLogos": "Les logos sont chargés depuis les domaines des marques avec une icône locale en secours.", "brandLogos": "Affiche les logos de fournisseurs tiers et CLI dans les Réglages.",
"cliAppsCatalog": "Parcourez les CLIs d'apps que nanobot peut exécuter localement.", "cliAppsCatalog": "Installe uniquement les adaptateurs CLI dapps que nanobot peut exécuter localement ; les apps natives restent inchangées.",
"cliAppsFilter": "Recherchez par app, catégorie ou capacité.", "cliAppsFilter": "Recherchez par app, catégorie ou capacité.",
"logs": "Ouvrir le dossier des journaux du moteur natif.", "logs": "Ouvre le dossier des journaux du moteur natif.",
"diagnostics": "Exporter un petit rapport runtime pour le support.", "diagnostics": "Exporte un petit rapport dexécution pour le support.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Autorise les commandes shell Full Access à atteindre les services sur ce Mac.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "Utilisé par les chats natifs sans permission propre au projet.",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "Choisissez le budget de contexte par défaut pour cette configuration de modèle."
}, },
"values": { "values": {
"light": "Clair", "light": "Clair",
"dark": "Sombre", "dark": "Sombre",
"notAvailable": "Indisponible", "notAvailable": "Indisponible",
"enabled": "Enabled", "enabled": "Activé",
"disabled": "Disabled", "disabled": "Désactivé",
"restartPending": "Redémarrage en attente", "restartPending": "Redémarrage en attente",
"ready": "Prêt", "ready": "Prêt",
"comfortable": "Comfortable", "comfortable": "Confortable",
"compact": "Compact", "compact": "Compacte",
"auto": "Auto", "auto": "Automatique",
"expanded": "Expanded", "expanded": "Développé",
"on": "On", "on": "Activé",
"off": "Off", "off": "Désactivé",
"defaultPermission": "Default Permission", "defaultPermission": "Autorisation par défaut",
"fullAccess": "Full Access", "fullAccess": "Accès complet",
"configured": "Configured", "configured": "Configuré",
"notConfigured": "Not configured", "notConfigured": "Non configuré",
"pending": "En attente", "pending": "En attente",
"restartingEngine": "Redémarrage" "restartingEngine": "Redémarrage"
}, },
"status": { "status": {
"loading": "Chargement des paramètres...", "loading": "Chargement des réglages...",
"loadError": "Impossible de charger les paramètres", "loadError": "Impossible de charger les réglages",
"unsaved": "Modifications non enregistrées.", "unsaved": "Modifications non enregistrées.",
"upToDate": "À jour.", "upToDate": "À jour.",
"savedRestart": "Enregistré. Redémarrez nanobot pour appliquer.", "savedRestart": "Enregistré. Redémarrez nanobot pour appliquer.",
"restartAfterSaving": "Enregistrez les modifications, puis redémarrez lorsque vous êtes prêt.", "restartAfterSaving": "Enregistrez les changements, puis redémarrez quand vous êtes prêt.",
"savedRestartApply": "Enregistré. Redémarrez lorsque vous êtes prêt.", "savedRestartApply": "Enregistré. Redémarrez quand vous êtes prêt.",
"imageProviderRestart": "Modifications du fournisseur dimages enregistrées. Redémarrez lorsque vous êtes prêt.", "imageProviderRestart": "Changements du fournisseur dimage enregistrés. Redémarrez quand vous êtes prêt.",
"hostRestartAfterSaving": "Enregistrez les changements et nanobot redémarrera son moteur.", "hostRestartAfterSaving": "En enregistrant, nanobot redémarrera son moteur.",
"hostRestartPending": "Enregistré. Redémarrage du moteur quand il sera prêt.", "hostRestartPending": "Enregistré. Le moteur redémarrera lorsquil sera prêt.",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "Les actions de lhôte ne sont disponibles que dans lapp native.",
"logsOpened": "Opened logs folder.", "logsOpened": "Dossier des journaux ouvert.",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "Impossible douvrir le dossier des journaux.",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "Diagnostic exporté vers {{path}}.",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "Impossible dexporter le diagnostic."
}, },
"actions": { "actions": {
"save": "Enregistrer", "save": "Enregistrer",
@ -224,8 +224,8 @@
"cancel": "Annuler", "cancel": "Annuler",
"open": "Ouvrir", "open": "Ouvrir",
"export": "Exporter", "export": "Exporter",
"opening": "Opening...", "opening": "Ouverture...",
"exporting": "Exporting..." "exporting": "Exportation..."
}, },
"byok": { "byok": {
"description": "Utilisez vos propres clés de fournisseur. Nanobot lit ces valeurs depuis la configuration actuelle, et seuls les fournisseurs configurés peuvent être sélectionnés dans Général.", "description": "Utilisez vos propres clés de fournisseur. Nanobot lit ces valeurs depuis la configuration actuelle, et seuls les fournisseurs configurés peuvent être sélectionnés dans Général.",
@ -250,7 +250,7 @@
"tabs": { "tabs": {
"ariaLabel": "Type d'identifiants BYOK", "ariaLabel": "Type d'identifiants BYOK",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "Recherche web"
}, },
"webSearch": { "webSearch": {
"provider": "Fournisseur de recherche", "provider": "Fournisseur de recherche",
@ -270,53 +270,53 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "Modèle actuel",
"providers": "Providers", "providers": "Fournisseurs",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}} configurés",
"totalProviders": "{{count}} available", "totalProviders": "{{count}} disponibles",
"webSearch": "Web search", "webSearch": "Recherche web",
"imageGeneration": "Génération d'images", "imageGeneration": "Génération dimages",
"workspace": "Workspace" "workspace": "Espace de travail"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "Rechercher des fournisseurs",
"noMatches": "No providers match this search.", "noMatches": "Aucun fournisseur ne correspond.",
"saveProvider": "Enregistrer le fournisseur" "saveProvider": "Enregistrer le fournisseur"
}, },
"image": { "image": {
"selectProvider": "Sélectionner un fournisseur", "selectProvider": "Choisir un fournisseur",
"selectAspect": "Sélectionner un format", "selectAspect": "Choisir un ratio",
"selectSize": "Sélectionner une taille", "selectSize": "Choisir une taille",
"configureProvider": "Configurer le fournisseur", "configureProvider": "Configurer le fournisseur",
"missingCredential": "Configurez ce fournisseur avant dactiver la génération dimages." "missingCredential": "Configura este proveedor antes de activar la generación de imágenes."
}, },
"models": { "models": {
"selectModel": "Sélectionner un modèle", "selectModel": "Choisir un modèle",
"addConfiguration": "Ajouter une configuration", "addConfiguration": "Ajouter une configuration",
"newConfiguration": "Nouvelle configuration de modèle", "newConfiguration": "Nouvelle configuration de modèle",
"newConfigurationHelp": "Enregistrez un fournisseur et un modèle comme option en un clic.", "newConfigurationHelp": "Enregistre un fournisseur et un modèle comme option en un clic.",
"configurationName": "Nom de la configuration", "configurationName": "Nom de la configuration",
"configurationNameHelp": "Renommez cette configuration de modèle enregistrée.", "configurationNameHelp": "Renomme cette configuration de modèle enregistrée.",
"configurationNamePlaceholder": "Rédaction rapide", "configurationNamePlaceholder": "Rédaction rapide",
"searchModels": "Rechercher ou saisir lID du modèle", "searchModels": "Rechercher ou saisir un ID de modèle",
"useCustomModel": "Utiliser", "useCustomModel": "Utiliser",
"loadingModels": "Chargement des modèles...", "loadingModels": "Chargement des modèles...",
"searchCatalog": "Recherchez dans le catalogue du fournisseur pour choisir un modèle.", "searchCatalog": "Rechercher dans le catalogue du fournisseur pour choisir un modèle.",
"modelsAvailable": "disponibles", "modelsAvailable": "disponibles",
"noModelResults": "Aucun modèle correspondant.", "noModelResults": "Aucun modèle correspondant.",
"loadFailed": "Liste des modèles indisponible.", "loadFailed": "Liste des modèles indisponible.",
"unsupportedModelList": "Saisissez manuellement un ID de modèle.", "unsupportedModelList": "Saisissez manuellement un ID de modèle.",
"providerNotConfigured": "Configurez ce fournisseur avant de charger les modèles.", "providerNotConfigured": "Configurez ce fournisseur avant de charger les modèles.",
"autoProviderCustomOnly": "Le mode fournisseur automatique utilise des ID de modèle personnalisés." "autoProviderCustomOnly": "Le mode fournisseur automatique utilise des IDs de modèle personnalisés."
}, },
"timezone": { "timezone": {
"select": "Sélectionner un fuseau horaire", "select": "Choisir un fuseau horaire",
"search": "Rechercher un fuseau horaire", "search": "Rechercher un fuseau horaire",
"empty": "Aucun fuseau horaire correspondant." "empty": "Aucun fuseau horaire correspondant."
}, },
"cliApps": { "cliApps": {
"allCategories": "Toutes les catégories", "allCategories": "Toutes les catégories",
"availableCount": "{{count}} apps", "availableCount": "{{count}} applications",
"installedCount": "{{count}} installées", "installedCount": "{{count}} installées",
"summary": "{{installed}} CLIs installées sur {{total}}", "summary": "{{installed}} CLIs installées sur {{total}}",
"filterAll": "Tout", "filterAll": "Tout",
@ -402,7 +402,7 @@
"thirdPartyBrands": "Les noms, logos et marques de produits appartiennent à leurs propriétaires respectifs. Leur utilisation sert uniquement à l'identification et n'implique aucune approbation." "thirdPartyBrands": "Les noms, logos et marques de produits appartiennent à leurs propriétaires respectifs. Leur utilisation sert uniquement à l'identification et n'implique aucune approbation."
}, },
"apps": { "apps": {
"description": "Ajoutez des CLI dapps et des services MCP que nanobot peut utiliser dans le chat.", "description": "Ajoutez des CLI dapps et services MCP utilisables par nanobot depuis le chat.",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "Tout", "filterAll": "Tout",
@ -411,22 +411,22 @@
"enabledSummary": "{{count}} activés", "enabledSummary": "{{count}} activés",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "{{cli}} CLI · {{mcp}} MCP",
"searchPlaceholder": "Rechercher des apps", "searchPlaceholder": "Rechercher des apps",
"featured": "En vedette", "featured": "À la une",
"loading": "Chargement des apps...", "loading": "Chargement des apps...",
"empty": "Aucune app ne correspond à ce filtre." "empty": "Aucune app ne correspond."
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "Authentification OAuth",
"signIn": "Sign in", "signIn": "Se connecter",
"signingIn": "Signing in...", "signingIn": "Connexion...",
"signInAgain": "Sign in again", "signInAgain": "Se reconnecter",
"signOut": "Sign out", "signOut": "Se déconnecter",
"signedInAs": "Signed in as {{account}}", "signedInAs": "Connecté en tant que {{account}}",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "Inicia sesión desde este dispositivo; no se guarda API key en config.",
"signInRequired": "Sign in required", "signInRequired": "Connexion requise",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "Inicia sesión antes de guardar este proveedor OAuth como proveedor activo.",
"signedIn": "Signed in", "signedIn": "Connecté",
"notSignedIn": "Not signed in" "notSignedIn": "Non connecté"
} }
}, },
"chat": { "chat": {

View File

@ -57,7 +57,7 @@
"apps": "Aplikasi" "apps": "Aplikasi"
}, },
"settings": { "settings": {
"backToChat": "Kembali ke obrolan", "backToChat": "Kembali ke chat",
"sidebar": { "sidebar": {
"title": "Pengaturan", "title": "Pengaturan",
"ariaLabel": "Bagian pengaturan" "ariaLabel": "Bagian pengaturan"
@ -65,14 +65,14 @@
"nav": { "nav": {
"general": "Umum", "general": "Umum",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "Ikhtisar",
"appearance": "Appearance", "appearance": "Tampilan",
"models": "Models", "models": "Model",
"providers": "Providers", "providers": "Penyedia",
"image": "Image", "image": "Gambar",
"browser": "Web", "browser": "Internet",
"runtime": "Sistem", "runtime": "Sistem",
"advanced": "Security", "advanced": "Keamanan",
"cliApps": "Aplikasi CLI", "cliApps": "Aplikasi CLI",
"mcp": "MCP", "mcp": "MCP",
"apps": "Aplikasi" "apps": "Aplikasi"
@ -82,20 +82,20 @@
"ai": "AI", "ai": "AI",
"system": "Sistem", "system": "Sistem",
"status": "Status", "status": "Status",
"localPreferences": "Local preferences", "localPreferences": "Preferensi lokal",
"presets": "Presets", "presets": "Preset",
"imageGeneration": "Pembuatan gambar", "imageGeneration": "Pembuatan gambar",
"imageDefaults": "Default", "imageDefaults": "Default",
"webSearch": "Web search", "webSearch": "Pencarian web",
"webBehavior": "Behavior", "webBehavior": "Perilaku",
"identity": "Identity", "identity": "Identitas",
"webuiSafety": "Web safety", "webuiSafety": "Keamanan WebUI",
"capabilities": "Kapabilitas", "capabilities": "Kemampuan",
"cliApps": "App CLI", "cliApps": "Aplikasi CLI",
"mcp": "Layanan MCP", "mcp": "Layanan MCP",
"apps": "Aplikasi", "apps": "Aplikasi",
"nativeHost": "Native host", "nativeHost": "Host native",
"hostSafety": "App safety" "hostSafety": "Keamanan aplikasi"
}, },
"rows": { "rows": {
"theme": "Tema", "theme": "Tema",
@ -104,18 +104,18 @@
"model": "Model", "model": "Model",
"restart": "Mulai ulang nanobot", "restart": "Mulai ulang nanobot",
"configPath": "Path konfigurasi", "configPath": "Path konfigurasi",
"activePreset": "Active preset", "activePreset": "Preset aktif",
"gateway": "Gateway", "gateway": "Gerbang",
"restartState": "Restart state", "restartState": "Status mulai ulang",
"pendingChanges": "Perubahan tertunda", "pendingChanges": "Perubahan tertunda",
"selectedPreset": "Selected preset", "selectedPreset": "Preset terpilih",
"presetModel": "Preset model", "presetModel": "Model preset",
"density": "Density", "density": "Kerapatan",
"activityMode": "Activity detail", "activityMode": "Detail aktivitas",
"codeWrap": "Code wrapping", "codeWrap": "Bungkus kode",
"maxResults": "Max results", "maxResults": "Hasil maksimum",
"timeout": "Timeout", "timeout": "Batas waktu",
"jinaReader": "Jina reader", "jinaReader": "Pembaca Jina",
"imageGeneration": "Pembuatan gambar", "imageGeneration": "Pembuatan gambar",
"imageProvider": "Penyedia gambar", "imageProvider": "Penyedia gambar",
"imageProviderStatus": "Status penyedia", "imageProviderStatus": "Status penyedia",
@ -124,98 +124,98 @@
"defaultAspectRatio": "Rasio default", "defaultAspectRatio": "Rasio default",
"defaultImageSize": "Ukuran default", "defaultImageSize": "Ukuran default",
"maxImagesPerTurn": "Maks. gambar per giliran", "maxImagesPerTurn": "Maks. gambar per giliran",
"imageSaveDir": "Direktori penyimpanan", "imageSaveDir": "Direktori simpan",
"botName": "Bot name", "botName": "Nama bot",
"botIcon": "Bot icon", "botIcon": "Ikon bot",
"timezone": "Timezone", "timezone": "Zona waktu",
"workspacePath": "Workspace default", "workspacePath": "Workspace default",
"localServiceAccess": "Local services", "localServiceAccess": "Layanan lokal",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "Akses default",
"currentModel": "Konfigurasi saat ini", "currentModel": "Konfigurasi saat ini",
"brandLogos": "Logo merek", "brandLogos": "Logo merek",
"cliAppsCatalog": "Katalog aplikasi CLI", "cliAppsCatalog": "Katalog",
"cliAppsFilter": "Filter aplikasi CLI", "cliAppsFilter": "Saring",
"engine": "Engine", "engine": "Mesin",
"logs": "Log", "logs": "Log",
"diagnostics": "Diagnostik", "diagnostics": "Diagnostik",
"contextWindow": "Context window" "contextWindow": "Jendela konteks"
}, },
"help": { "help": {
"theme": "Beralih antara tampilan terang dan gelap.", "theme": "Beralih antara tampilan terang dan gelap.",
"language": "Pilih bahasa yang digunakan WebUI.", "language": "Pilih bahasa yang digunakan WebUI.",
"provider": "Pilih penyedia untuk permintaan model baru.", "provider": "Selecciona el proveedor para nuevas solicitudes de modelo.",
"model": "Atur nama model default yang digunakan nanobot.", "model": "Define el nombre de modelo predeterminado de nanobot.",
"configPath": "File konfigurasi gateway yang sedang digunakan.", "configPath": "Archivo de configuración que usa actualmente el gateway.",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "Los preajustes con nombre son de solo lectura aquí; edítalos en config.json.",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Beralih ke Default untuk mengedit model dan penyedia dari WebUI.",
"density": "Stored only in this browser.", "density": "Hanya disimpan di browser ini.",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "Pilih seberapa banyak detail aktivitas agen yang ditampilkan secara default.",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "Menjaga baris kode panjang tetap terbaca di layar kecil.",
"maxResults": "Results returned by each web_search call.", "maxResults": "Resultados devueltos por cada llamada web_search.",
"timeout": "Seconds before a search provider request times out.", "timeout": "Segundos antes de que una solicitud de búsqueda expire.",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "Usa Jina Reader para web_fetch cuando esté disponible.",
"imageGeneration": "Tampilkan generate_image di chat saat penyedia gambar yang dikonfigurasi tersedia.", "imageGeneration": "Expone generate_image en chats cuando hay un proveedor de imagen configurado.",
"imageProvider": "Pilih penyedia registry yang digunakan oleh generate_image.", "imageProvider": "Elige el proveedor registrado usado por generate_image.",
"imageProviderStatus": "Pembuatan gambar menggunakan ulang kredensial penyedia dari Providers.", "imageProviderStatus": "La generación de imágenes reutiliza credenciales de Proveedores.",
"imageModel": "Nama model yang dikirim ke penyedia gambar yang dipilih.", "imageModel": "Nombre del modelo enviado al proveedor de imágenes seleccionado.",
"defaultAspectRatio": "Digunakan saat prompt tidak memilih rasio aspek.", "defaultAspectRatio": "Se usa cuando el prompt no elige una proporción.",
"defaultImageSize": "Petunjuk ukuran yang dikirim ke penyedia yang mendukungnya.", "defaultImageSize": "Petunjuk ukuran yang dikirim ke penyedia yang mendukungnya.",
"maxImagesPerTurn": "Batas atas untuk satu permintaan generate_image.", "maxImagesPerTurn": "Batas atas untuk satu permintaan generate_image.",
"botName": "Ditampilkan di tempat nanobot memakai nama tampilan.", "botName": "Se muestra donde nanobot usa un nombre visible.",
"botIcon": "Emoji atau teks pendek yang tampil bersama nama bot.", "botIcon": "Emoji o texto corto junto al nombre del bot.",
"timezone": "Dipakai untuk jadwal dan balasan yang peka waktu.", "timezone": "Se usa para horarios y respuestas con conciencia temporal.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Izinkan perintah shell Full Access menjangkau layanan localhost.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "Digunakan oleh chat web tanpa izin khusus proyek.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "Las capturas web siempre protegen servicios locales, privados y metadata. La seguridad de canales core se gestiona en config.json.",
"currentModel": "Pilih konfigurasi model yang digunakan nanobot untuk balasan berikutnya.", "currentModel": "Digunakan untuk balasan baru.",
"selectedModelProvider": "Ditentukan oleh model yang dipilih.", "selectedModelProvider": "Definido por el modelo seleccionado.",
"selectedModelValue": "Ditentukan oleh model yang dipilih.", "selectedModelValue": "Definido por el modelo seleccionado.",
"brandLogos": "Logo dimuat dari domain merek dengan ikon lokal sebagai cadangan.", "brandLogos": "Tampilkan logo penyedia pihak ketiga dan CLI di Pengaturan.",
"cliAppsCatalog": "Jelajahi CLI aplikasi yang dapat dijalankan nanobot secara lokal.", "cliAppsCatalog": "Instala solo adaptadores CLI de apps que nanobot puede ejecutar localmente; las apps nativas no se modifican.",
"cliAppsFilter": "Cari berdasarkan aplikasi, kategori, atau kemampuan.", "cliAppsFilter": "Busca por app, categoría o capacidad.",
"logs": "Buka folder log native engine.", "logs": "Abre la carpeta de registros del motor nativo.",
"diagnostics": "Ekspor laporan runtime kecil untuk dukungan.", "diagnostics": "Exporta un pequeño informe de runtime para soporte.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Permite que comandos shell con Full Access alcancen servicios en este Mac.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "Usado por chats nativos sin permiso específico de proyecto.",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "Pilih anggaran konteks default untuk konfigurasi model ini."
}, },
"values": { "values": {
"light": "Terang", "light": "Terang",
"dark": "Gelap", "dark": "Gelap",
"notAvailable": "Tidak tersedia", "notAvailable": "Tidak tersedia",
"enabled": "Enabled", "enabled": "Aktif",
"disabled": "Disabled", "disabled": "Nonaktif",
"restartPending": "Menunggu restart", "restartPending": "Menunggu mulai ulang",
"ready": "Siap", "ready": "Siap",
"comfortable": "Comfortable", "comfortable": "Nyaman",
"compact": "Compact", "compact": "Ringkas",
"auto": "Auto", "auto": "Otomatis",
"expanded": "Expanded", "expanded": "Diperluas",
"on": "On", "on": "Aktif",
"off": "Off", "off": "Nonaktif",
"defaultPermission": "Default Permission", "defaultPermission": "Izin default",
"fullAccess": "Full Access", "fullAccess": "Akses penuh",
"configured": "Configured", "configured": "Terkonfigurasi",
"notConfigured": "Not configured", "notConfigured": "Belum dikonfigurasi",
"pending": "Tertunda", "pending": "Tertunda",
"restartingEngine": "Memulai ulang" "restartingEngine": "Memulai ulang"
}, },
"status": { "status": {
"loading": "Memuat pengaturan...", "loading": "Memuat pengaturan...",
"loadError": "Tidak dapat memuat pengaturan", "loadError": "Tidak dapat memuat pengaturan",
"unsaved": "Ada perubahan yang belum disimpan.", "unsaved": "Perubahan belum disimpan.",
"upToDate": "Sudah terbaru.", "upToDate": "Sudah terbaru.",
"savedRestart": "Tersimpan. Mulai ulang nanobot untuk menerapkan.", "savedRestart": "Guardado. Reinicia nanobot para aplicar.",
"restartAfterSaving": "Simpan perubahan, lalu restart saat siap.", "restartAfterSaving": "Guarda los cambios y reinicia cuando puedas.",
"savedRestartApply": "Tersimpan. Restart saat siap.", "savedRestartApply": "Guardado. Reinicia cuando puedas.",
"imageProviderRestart": "Perubahan penyedia gambar tersimpan. Restart saat siap.", "imageProviderRestart": "Cambios del proveedor de imagen guardados. Reinicia cuando puedas.",
"hostRestartAfterSaving": "Simpan perubahan dan nanobot akan memulai ulang engine.", "hostRestartAfterSaving": "Al guardar, nanobot reiniciará su motor.",
"hostRestartPending": "Tersimpan. Engine akan dimulai ulang saat siap.", "hostRestartPending": "Guardado. El motor se reiniciará cuando esté listo.",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "Las acciones del host solo están disponibles en la app nativa.",
"logsOpened": "Opened logs folder.", "logsOpened": "Carpeta de registros abierta.",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "No se pudo abrir la carpeta de registros.",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "Diagnóstico exportado a {{path}}.",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "No se pudo exportar el diagnóstico."
}, },
"actions": { "actions": {
"save": "Simpan", "save": "Simpan",
@ -224,8 +224,8 @@
"cancel": "Batal", "cancel": "Batal",
"open": "Buka", "open": "Buka",
"export": "Ekspor", "export": "Ekspor",
"opening": "Opening...", "opening": "Membuka...",
"exporting": "Exporting..." "exporting": "Mengekspor..."
}, },
"byok": { "byok": {
"description": "Gunakan kunci provider Anda sendiri. Nanobot membaca nilai ini dari config saat ini, dan hanya provider yang sudah dikonfigurasi yang bisa dipilih di Umum.", "description": "Gunakan kunci provider Anda sendiri. Nanobot membaca nilai ini dari config saat ini, dan hanya provider yang sudah dikonfigurasi yang bisa dipilih di Umum.",
@ -250,10 +250,10 @@
"tabs": { "tabs": {
"ariaLabel": "Jenis kredensial BYOK", "ariaLabel": "Jenis kredensial BYOK",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "Pencarian web"
}, },
"webSearch": { "webSearch": {
"provider": "Search provider", "provider": "Penyedia pencarian",
"providerHelp": "Pilih backend yang digunakan alat web search.", "providerHelp": "Pilih backend yang digunakan alat web search.",
"selectProvider": "Pilih provider", "selectProvider": "Pilih provider",
"credentials": "Kredensial", "credentials": "Kredensial",
@ -270,17 +270,17 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "Model saat ini",
"providers": "Providers", "providers": "Penyedia",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}} dikonfigurasi",
"totalProviders": "{{count}} available", "totalProviders": "{{count}} tersedia",
"webSearch": "Web search", "webSearch": "Pencarian web",
"imageGeneration": "Pembuatan gambar", "imageGeneration": "Pembuatan gambar",
"workspace": "Workspace" "workspace": "Ruang kerja"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "Cari penyedia",
"noMatches": "No providers match this search.", "noMatches": "Tidak ada penyedia yang cocok.",
"saveProvider": "Simpan penyedia" "saveProvider": "Simpan penyedia"
}, },
"image": { "image": {
@ -288,7 +288,7 @@
"selectAspect": "Pilih rasio", "selectAspect": "Pilih rasio",
"selectSize": "Pilih ukuran", "selectSize": "Pilih ukuran",
"configureProvider": "Konfigurasi penyedia", "configureProvider": "Konfigurasi penyedia",
"missingCredential": "Konfigurasikan penyedia ini sebelum mengaktifkan pembuatan gambar." "missingCredential": "Configura este proveedor antes de activar la generación de imágenes."
}, },
"models": { "models": {
"selectModel": "Pilih model", "selectModel": "Pilih model",
@ -296,8 +296,8 @@
"newConfiguration": "Konfigurasi model baru", "newConfiguration": "Konfigurasi model baru",
"newConfigurationHelp": "Simpan penyedia dan model sebagai opsi sekali klik.", "newConfigurationHelp": "Simpan penyedia dan model sebagai opsi sekali klik.",
"configurationName": "Nama konfigurasi", "configurationName": "Nama konfigurasi",
"configurationNameHelp": "Ganti nama konfigurasi model yang tersimpan ini.", "configurationNameHelp": "Ganti nama konfigurasi model tersimpan ini.",
"configurationNamePlaceholder": "Penulisan cepat", "configurationNamePlaceholder": "Menulis cepat",
"searchModels": "Cari atau ketik ID model", "searchModels": "Cari atau ketik ID model",
"useCustomModel": "Gunakan", "useCustomModel": "Gunakan",
"loadingModels": "Memuat model...", "loadingModels": "Memuat model...",
@ -307,7 +307,7 @@
"loadFailed": "Daftar model tidak tersedia.", "loadFailed": "Daftar model tidak tersedia.",
"unsupportedModelList": "Ketik ID model secara manual.", "unsupportedModelList": "Ketik ID model secara manual.",
"providerNotConfigured": "Konfigurasikan penyedia ini sebelum memuat model.", "providerNotConfigured": "Konfigurasikan penyedia ini sebelum memuat model.",
"autoProviderCustomOnly": "Mode penyedia otomatis menggunakan ID model khusus." "autoProviderCustomOnly": "Mode penyedia otomatis memakai ID model kustom."
}, },
"timezone": { "timezone": {
"select": "Pilih zona waktu", "select": "Pilih zona waktu",
@ -402,31 +402,31 @@
"thirdPartyBrands": "Nama produk, logo, dan merek adalah milik pemiliknya masing-masing. Penggunaan hanya untuk identifikasi dan tidak menyiratkan dukungan." "thirdPartyBrands": "Nama produk, logo, dan merek adalah milik pemiliknya masing-masing. Penggunaan hanya untuk identifikasi dan tidak menyiratkan dukungan."
}, },
"apps": { "apps": {
"description": "Tambahkan CLI app dan layanan MCP yang dapat digunakan nanobot dari chat.", "description": "Tambahkan CLI aplikasi dan layanan MCP yang dapat digunakan nanobot dari chat.",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "Semua", "filterAll": "Semua",
"filterCli": "App CLI", "filterCli": "Aplikasi CLI",
"filterMcp": "Layanan MCP", "filterMcp": "Layanan MCP",
"enabledSummary": "{{count}} aktif", "enabledSummary": "{{count}} aktif",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "{{cli}} CLI · {{mcp}} MCP",
"searchPlaceholder": "Cari aplikasi", "searchPlaceholder": "Cari aplikasi",
"featured": "Unggulan", "featured": "Unggulan",
"loading": "Memuat aplikasi...", "loading": "Memuat aplikasi...",
"empty": "Tidak ada aplikasi yang cocok dengan filter ini." "empty": "Tidak ada aplikasi yang cocok."
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "Autentikasi OAuth",
"signIn": "Sign in", "signIn": "Masuk",
"signingIn": "Signing in...", "signingIn": "Masuk...",
"signInAgain": "Sign in again", "signInAgain": "Masuk lagi",
"signOut": "Sign out", "signOut": "Keluar",
"signedInAs": "Signed in as {{account}}", "signedInAs": "Masuk sebagai {{account}}",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "Inicia sesión desde este dispositivo; no se guarda API key en config.",
"signInRequired": "Sign in required", "signInRequired": "Perlu masuk",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "Inicia sesión antes de guardar este proveedor OAuth como proveedor activo.",
"signedIn": "Signed in", "signedIn": "Sudah masuk",
"notSignedIn": "Not signed in" "notSignedIn": "Belum masuk"
} }
}, },
"chat": { "chat": {

View File

@ -65,14 +65,14 @@
"nav": { "nav": {
"general": "一般", "general": "一般",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "概要",
"appearance": "Appearance", "appearance": "外観",
"models": "Models", "models": "モデル",
"providers": "Providers", "providers": "プロバイダー",
"image": "Image", "image": "画像",
"browser": "Web", "browser": "ウェブ",
"runtime": "システム", "runtime": "システム",
"advanced": "Security", "advanced": "セキュリティ",
"cliApps": "CLI アプリ", "cliApps": "CLI アプリ",
"mcp": "MCP", "mcp": "MCP",
"apps": "アプリ" "apps": "アプリ"
@ -81,21 +81,21 @@
"interface": "インターフェース", "interface": "インターフェース",
"ai": "AI", "ai": "AI",
"system": "システム", "system": "システム",
"status": "Status", "status": "状態",
"localPreferences": "Local preferences", "localPreferences": "ローカル設定",
"presets": "Presets", "presets": "プリセット",
"imageGeneration": "画像生成", "imageGeneration": "画像生成",
"imageDefaults": "既定値", "imageDefaults": "既定値",
"webSearch": "Web search", "webSearch": "ウェブ検索",
"webBehavior": "Behavior", "webBehavior": "動作",
"identity": "Identity", "identity": "ID",
"webuiSafety": "Web safety", "webuiSafety": "WebUI の安全性",
"capabilities": "機能", "capabilities": "機能",
"cliApps": "CLI アプリ", "cliApps": "CLI アプリ",
"mcp": "MCP サービス", "mcp": "MCP サービス",
"apps": "アプリ", "apps": "アプリ",
"nativeHost": "App", "nativeHost": "ネイティブホスト",
"hostSafety": "App safety" "hostSafety": "アプリの安全性"
}, },
"rows": { "rows": {
"theme": "テーマ", "theme": "テーマ",
@ -104,41 +104,41 @@
"model": "モデル", "model": "モデル",
"restart": "nanobot を再起動", "restart": "nanobot を再起動",
"configPath": "設定パス", "configPath": "設定パス",
"activePreset": "Active preset", "activePreset": "アクティブなプリセット",
"gateway": "Gateway", "gateway": "ゲートウェイ",
"restartState": "Restart state", "restartState": "再起動状態",
"pendingChanges": "保留中の変更", "pendingChanges": "保留中の変更",
"selectedPreset": "Selected preset", "selectedPreset": "選択中のプリセット",
"presetModel": "Preset model", "presetModel": "プリセットモデル",
"density": "Density", "density": "表示密度",
"activityMode": "Activity detail", "activityMode": "アクティビティ詳細",
"codeWrap": "Code wrapping", "codeWrap": "コードの折り返し",
"maxResults": "Max results", "maxResults": "最大結果数",
"timeout": "Timeout", "timeout": "タイムアウト",
"jinaReader": "Jina reader", "jinaReader": "Jina リーダー",
"imageGeneration": "画像生成", "imageGeneration": "画像生成",
"imageProvider": "画像プロバイダー", "imageProvider": "画像プロバイダー",
"imageProviderStatus": "プロバイダー状態", "imageProviderStatus": "プロバイダー状態",
"imageProviderBase": "プロバイダーのベース URL", "imageProviderBase": "プロバイダー URL",
"imageModel": "画像モデル", "imageModel": "画像モデル",
"defaultAspectRatio": "既定の比率", "defaultAspectRatio": "既定の比率",
"defaultImageSize": "既定のサイズ", "defaultImageSize": "既定のサイズ",
"maxImagesPerTurn": "1 ターンあたりの最大画像数", "maxImagesPerTurn": "1 ターンの最大画像数",
"imageSaveDir": "保存先ディレクトリ", "imageSaveDir": "保存先ディレクトリ",
"botName": "Bot name", "botName": "Bot ",
"botIcon": "Bot icon", "botIcon": "Bot アイコン",
"timezone": "Timezone", "timezone": "タイムゾーン",
"workspacePath": "デフォルトワークスペース", "workspacePath": "既定のワークスペース",
"localServiceAccess": "Local services", "localServiceAccess": "ローカルサービス",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "既定の権限",
"currentModel": "現在の設定", "currentModel": "現在の設定",
"brandLogos": "ブランドロゴ", "brandLogos": "ブランドロゴ",
"cliAppsCatalog": "CLI アプリカタログ", "cliAppsCatalog": "カタログ",
"cliAppsFilter": "CLI アプリフィルター", "cliAppsFilter": "フィルター",
"engine": "エンジン", "engine": "エンジン",
"logs": "ログ", "logs": "ログ",
"diagnostics": "診断", "diagnostics": "診断",
"contextWindow": "Context window" "contextWindow": "コンテキストウィンドウ"
}, },
"help": { "help": {
"theme": "ライト表示とダーク表示を切り替えます。", "theme": "ライト表示とダーク表示を切り替えます。",
@ -146,57 +146,57 @@
"provider": "新しいモデルリクエストに使うプロバイダーを選択します。", "provider": "新しいモデルリクエストに使うプロバイダーを選択します。",
"model": "nanobot が既定で使用するモデル名を設定します。", "model": "nanobot が既定で使用するモデル名を設定します。",
"configPath": "現在ゲートウェイが使用している設定ファイルです。", "configPath": "現在ゲートウェイが使用している設定ファイルです。",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "名前付きプリセットはここでは読み取り専用です。編集するには config.json を変更してください。",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Default に切り替えると、WebUI からモデルとプロバイダーを編集できます。",
"density": "Stored only in this browser.", "density": "このブラウザーにのみ保存されます。",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "既定で表示する agent アクティビティの詳細量を選択します。",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "小さな画面でも長いコード行を読みやすくします。",
"maxResults": "Results returned by each web_search call.", "maxResults": "各 web_search 呼び出しで返す結果数です。",
"timeout": "Seconds before a search provider request times out.", "timeout": "検索プロバイダーのリクエストがタイムアウトするまでの秒数です。",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "利用可能な場合、web_fetch に Jina Reader を使います。",
"imageGeneration": "設定済みの画像プロバイダーが利用できる場合、チャットで generate_image を有効にします。", "imageGeneration": "画像プロバイダーが設定済みのとき、チャットで generate_image を有効にします。",
"imageProvider": "generate_image で使用する登録済みプロバイダーを選択します。", "imageProvider": "generate_image で使用する登録済みプロバイダーを選択します。",
"imageProviderStatus": "画像生成は「プロバイダー」の認証情報を再利用します。", "imageProviderStatus": "画像生成は「プロバイダー」の認証情報を再利用します。",
"imageModel": "選択した画像プロバイダーへ送信するモデル名です。", "imageModel": "選択した画像プロバイダーへ送信するモデル名です。",
"defaultAspectRatio": "プロンプトでアスペクト比が指定されていない場合に使用します。", "defaultAspectRatio": "プロンプトでが指定されていない場合に使用します。",
"defaultImageSize": "対応しているプロバイダーへ送信するサイズ指定です。", "defaultImageSize": "対応しているプロバイダーへ送信するサイズ指定です。",
"maxImagesPerTurn": "1 回の generate_image リクエストで生成できる画像数の上限です。", "maxImagesPerTurn": "1 回の generate_image リクエストで生成できる画像数の上限です。",
"botName": "nanobot が表示名を使う場所に表示されます。", "botName": "nanobot が表示名を使う場所に表示されます。",
"botIcon": "Bot 名の横に表示する短い emoji またはテキストです。", "botIcon": "Bot 名の横に表示する短い emoji またはテキストです。",
"timezone": "スケジュールと時刻を考慮する返信に使用します。", "timezone": "スケジュールと時刻を考慮する返信に使用します。",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Full Access の shell コマンドが localhost サービスにアクセスできるようにします。",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "プロジェクト固有の権限がない Web チャットで使用します。",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "Web 取得は常にローカル、プライベート、メタデータサービスを保護します。コアチャネルの安全性は config.json で管理されます。",
"currentModel": "今後の返信で nanobot が使用するモデル設定を選択します。", "currentModel": "新しい返信に使用します。",
"selectedModelProvider": "選択したモデルによって設定されます。", "selectedModelProvider": "選択したモデルによって設定されます。",
"selectedModelValue": "選択したモデルによって設定されます。", "selectedModelValue": "選択したモデルによって設定されます。",
"brandLogos": "ロゴはブランドのドメインから読み込まれ、ローカルアイコンにフォールバックします。", "brandLogos": "設定で第三者プロバイダーと CLI のロゴを表示します。",
"cliAppsCatalog": "nanobot がローカルで実行できるアプリ CLI を探します。", "cliAppsCatalog": "nanobot がローカルで実行できるアプリ CLI アダプターだけをインストールします。ネイティブアプリは変更しません。",
"cliAppsFilter": "アプリ、カテゴリ、機能で検索します。", "cliAppsFilter": "アプリ、カテゴリ、機能で検索します。",
"logs": "Appエンジンのログフォルダを開きます。", "logs": "ネイティブエンジンのログフォルダーを開きます。",
"diagnostics": "サポート用の小さなランタイムレポートを書き出します。", "diagnostics": "サポート用の小さなランタイムレポートを書き出します。",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Full Access の shell コマンドがこの Mac 上のサービスにアクセスできるようにします。",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "プロジェクト固有の権限がないネイティブチャットで使用します。",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "このモデル設定で使う既定のコンテキスト予算を選択します。"
}, },
"values": { "values": {
"light": "ライト", "light": "ライト",
"dark": "ダーク", "dark": "ダーク",
"notAvailable": "利用不可", "notAvailable": "利用不可",
"enabled": "Enabled", "enabled": "有効",
"disabled": "Disabled", "disabled": "無効",
"restartPending": "再起動待ち", "restartPending": "再起動待ち",
"ready": "準備完了", "ready": "準備完了",
"comfortable": "Comfortable", "comfortable": "標準",
"compact": "Compact", "compact": "コンパクト",
"auto": "Auto", "auto": "自動",
"expanded": "Expanded", "expanded": "展開",
"on": "On", "on": "オン",
"off": "Off", "off": "オフ",
"defaultPermission": "Default Permission", "defaultPermission": "既定の権限",
"fullAccess": "Full Access", "fullAccess": "完全アクセス",
"configured": "Configured", "configured": "設定済み",
"notConfigured": "Not configured", "notConfigured": "未設定",
"pending": "保留中", "pending": "保留中",
"restartingEngine": "再起動中" "restartingEngine": "再起動中"
}, },
@ -211,11 +211,11 @@
"imageProviderRestart": "画像プロバイダーの変更を保存しました。準備ができたら再起動してください。", "imageProviderRestart": "画像プロバイダーの変更を保存しました。準備ができたら再起動してください。",
"hostRestartAfterSaving": "保存すると nanobot がエンジンを再起動します。", "hostRestartAfterSaving": "保存すると nanobot がエンジンを再起動します。",
"hostRestartPending": "保存しました。準備ができたらエンジンを再起動します。", "hostRestartPending": "保存しました。準備ができたらエンジンを再起動します。",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "ホスト操作はネイティブアプリ内でのみ利用できます。",
"logsOpened": "Opened logs folder.", "logsOpened": "ログフォルダーを開きました。",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "ログフォルダーを開けませんでした。",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "診断を {{path}} に書き出しました。",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "診断を書き出せませんでした。"
}, },
"actions": { "actions": {
"save": "保存", "save": "保存",
@ -224,8 +224,8 @@
"cancel": "キャンセル", "cancel": "キャンセル",
"open": "開く", "open": "開く",
"export": "書き出す", "export": "書き出す",
"opening": "Opening...", "opening": "開いています...",
"exporting": "Exporting..." "exporting": "書き出しています..."
}, },
"byok": { "byok": {
"description": "自分の provider キーを使います。Nanobot は現在の config から値を読み込み、設定済みの provider だけを一般設定で選択できます。", "description": "自分の provider キーを使います。Nanobot は現在の config から値を読み込み、設定済みの provider だけを一般設定で選択できます。",
@ -250,7 +250,7 @@
"tabs": { "tabs": {
"ariaLabel": "BYOK 認証情報タイプ", "ariaLabel": "BYOK 認証情報タイプ",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "ウェブ検索"
}, },
"webSearch": { "webSearch": {
"provider": "検索 provider", "provider": "検索 provider",
@ -270,17 +270,17 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "現在のモデル",
"providers": "Providers", "providers": "プロバイダー",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}} 個設定済み",
"totalProviders": "{{count}} available", "totalProviders": "{{count}} 個利用可能",
"webSearch": "Web search", "webSearch": "Web 検索",
"imageGeneration": "画像生成", "imageGeneration": "画像生成",
"workspace": "Workspace" "workspace": "ワークスペース"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "プロバイダーを検索",
"noMatches": "No providers match this search.", "noMatches": "一致するプロバイダーはありません。",
"saveProvider": "プロバイダーを保存" "saveProvider": "プロバイダーを保存"
}, },
"image": { "image": {
@ -297,12 +297,12 @@
"newConfigurationHelp": "プロバイダーとモデルをワンクリックの選択肢として保存します。", "newConfigurationHelp": "プロバイダーとモデルをワンクリックの選択肢として保存します。",
"configurationName": "設定名", "configurationName": "設定名",
"configurationNameHelp": "保存済みのモデル設定の名前を変更します。", "configurationNameHelp": "保存済みのモデル設定の名前を変更します。",
"configurationNamePlaceholder": "高速ライティング", "configurationNamePlaceholder": "高速執筆",
"searchModels": "検索またはモデル ID を入力", "searchModels": "モデル ID を検索または入力",
"useCustomModel": "使用", "useCustomModel": "使用",
"loadingModels": "モデルを読み込み中...", "loadingModels": "モデルを読み込んでいます...",
"searchCatalog": "プロバイダーのカタログを検索してモデルを選択します。", "searchCatalog": "プロバイダーのカタログからモデルを選択します。",
"modelsAvailable": "利用可能", "modelsAvailable": "利用可能",
"noModelResults": "一致するモデルはありません。", "noModelResults": "一致するモデルはありません。",
"loadFailed": "モデル一覧を利用できません。", "loadFailed": "モデル一覧を利用できません。",
"unsupportedModelList": "モデル ID を手動で入力してください。", "unsupportedModelList": "モデル ID を手動で入力してください。",
@ -402,31 +402,31 @@
"thirdPartyBrands": "製品名、ロゴ、ブランドはそれぞれの所有者に帰属します。使用は識別のみを目的とし、承認を意味するものではありません。" "thirdPartyBrands": "製品名、ロゴ、ブランドはそれぞれの所有者に帰属します。使用は識別のみを目的とし、承認を意味するものではありません。"
}, },
"apps": { "apps": {
"description": "チャットから nanobot が使えるアプリ CLI と MCP サービスを追加します。", "description": "nanobot がチャットで使用できる App CLI と MCP サービスを追加します。",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "すべて", "filterAll": "すべて",
"filterCli": "CLI アプリ", "filterCli": "CLI アプリ",
"filterMcp": "MCP サービス", "filterMcp": "MCP サービス",
"enabledSummary": "{{count}} 件有効", "enabledSummary": "{{count}} 件有効",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "CLI {{cli}} 件 · MCP {{mcp}} 件",
"searchPlaceholder": "アプリを検索", "searchPlaceholder": "アプリを検索",
"featured": "おすすめ", "featured": "注目",
"loading": "アプリを読み込み中...", "loading": "アプリを読み込み中...",
"empty": "このフィルターに一致するアプリはありません。" "empty": "一致するアプリはありません。"
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "OAuth 認証",
"signIn": "Sign in", "signIn": "サインイン",
"signingIn": "Signing in...", "signingIn": "サインイン中...",
"signInAgain": "Sign in again", "signInAgain": "再度サインイン",
"signOut": "Sign out", "signOut": "サインアウト",
"signedInAs": "Signed in as {{account}}", "signedInAs": "{{account}} としてサインイン済み",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "このデバイスからサインインします。API key は config に保存されません。",
"signInRequired": "Sign in required", "signInRequired": "サインインが必要です",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "この OAuth プロバイダーをアクティブなモデルプロバイダーとして保存する前にサインインしてください。",
"signedIn": "Signed in", "signedIn": "サインイン済み",
"notSignedIn": "Not signed in" "notSignedIn": "未サインイン"
} }
}, },
"chat": { "chat": {

View File

@ -65,14 +65,14 @@
"nav": { "nav": {
"general": "일반", "general": "일반",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "개요",
"appearance": "Appearance", "appearance": "외관",
"models": "Models", "models": "모델",
"providers": "Providers", "providers": "제공자",
"image": "Image", "image": "이미지",
"browser": "Web", "browser": "",
"runtime": "시스템", "runtime": "시스템",
"advanced": "Security", "advanced": "보안",
"cliApps": "CLI 앱", "cliApps": "CLI 앱",
"mcp": "MCP", "mcp": "MCP",
"apps": "앱" "apps": "앱"
@ -81,21 +81,21 @@
"interface": "인터페이스", "interface": "인터페이스",
"ai": "AI", "ai": "AI",
"system": "시스템", "system": "시스템",
"status": "Status", "status": "상태",
"localPreferences": "Local preferences", "localPreferences": "로컬 환경설정",
"presets": "Presets", "presets": "프리셋",
"imageGeneration": "이미지 생성", "imageGeneration": "이미지 생성",
"imageDefaults": "기본값", "imageDefaults": "기본값",
"webSearch": "Web search", "webSearch": "웹 검색",
"webBehavior": "Behavior", "webBehavior": "동작",
"identity": "Identity", "identity": "ID",
"webuiSafety": "Web safety", "webuiSafety": "WebUI 보안",
"capabilities": "기능", "capabilities": "기능",
"cliApps": "CLI 앱", "cliApps": "CLI 앱",
"mcp": "MCP 서비스", "mcp": "MCP 서비스",
"apps": "앱", "apps": "앱",
"nativeHost": "App", "nativeHost": "네이티브 호스트",
"hostSafety": "App safety" "hostSafety": "앱 보안"
}, },
"rows": { "rows": {
"theme": "테마", "theme": "테마",
@ -104,118 +104,118 @@
"model": "모델", "model": "모델",
"restart": "nanobot 재시작", "restart": "nanobot 재시작",
"configPath": "설정 경로", "configPath": "설정 경로",
"activePreset": "Active preset", "activePreset": "활성 프리셋",
"gateway": "Gateway", "gateway": "게이트웨이",
"restartState": "Restart state", "restartState": "재시작 상태",
"pendingChanges": "대기 중인 변경 사항", "pendingChanges": "대기 중인 변경",
"selectedPreset": "Selected preset", "selectedPreset": "선택한 프리셋",
"presetModel": "Preset model", "presetModel": "프리셋 모델",
"density": "Density", "density": "밀도",
"activityMode": "Activity detail", "activityMode": "활동 상세",
"codeWrap": "Code wrapping", "codeWrap": "코드 줄바꿈",
"maxResults": "Max results", "maxResults": "최대 결과 수",
"timeout": "Timeout", "timeout": "타임아웃",
"jinaReader": "Jina reader", "jinaReader": "Jina 리더",
"imageGeneration": "이미지 생성", "imageGeneration": "이미지 생성",
"imageProvider": "이미지 제공자", "imageProvider": "이미지 제공자",
"imageProviderStatus": "제공자 상태", "imageProviderStatus": "제공자 상태",
"imageProviderBase": "제공자 기준 주소", "imageProviderBase": "제공자 주소",
"imageModel": "이미지 모델", "imageModel": "이미지 모델",
"defaultAspectRatio": "기본 비율", "defaultAspectRatio": "기본 비율",
"defaultImageSize": "기본 크기", "defaultImageSize": "기본 크기",
"maxImagesPerTurn": "턴당 최대 이미지 수", "maxImagesPerTurn": "턴당 최대 이미지 수",
"imageSaveDir": "저장 디렉터리", "imageSaveDir": "저장 디렉터리",
"botName": "Bot name", "botName": "Bot 이름",
"botIcon": "Bot icon", "botIcon": "Bot 아이콘",
"timezone": "Timezone", "timezone": "시간대",
"workspacePath": "기본 작업공간", "workspacePath": "기본 작업공간",
"localServiceAccess": "Local services", "localServiceAccess": "로컬 서비스",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "기본 권한",
"currentModel": "현재 구성", "currentModel": "현재 구성",
"brandLogos": "브랜드 로고", "brandLogos": "브랜드 로고",
"cliAppsCatalog": "CLI 앱 카탈로그", "cliAppsCatalog": "카탈로그",
"cliAppsFilter": "CLI 앱 필터", "cliAppsFilter": "필터",
"engine": "엔진", "engine": "엔진",
"logs": "로그", "logs": "로그",
"diagnostics": "진단", "diagnostics": "진단",
"contextWindow": "Context window" "contextWindow": "컨텍스트 창"
}, },
"help": { "help": {
"theme": "밝은 모드와 어두운 모드를 전환합니다.", "theme": "밝은 모드와 어두운 모드를 전환합니다.",
"language": "WebUI에서 사용할 언어를 선택합니다.", "language": "WebUI에서 사용할 언어를 선택합니다.",
"provider": "새 모델 요청에 사용할 제공자를 선택합니다.", "provider": "새 모델 요청을 처리할 제공자를 선택합니다.",
"model": "nanobot이 기본으로 사용할 모델 이름을 설정합니다.", "model": "nanobot이 기본으로 사용할 모델 이름을 설정합니다.",
"configPath": "현재 게이트웨이가 사용하는 설정 파일입니다.", "configPath": "현재 게이트웨이가 사용하는 설정 파일입니다.",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "이름 있는 프리셋은 여기서 읽기 전용입니다. config.json에서 편집하세요.",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Default로 전환하면 WebUI에서 모델과 제공자를 편집할 수 있습니다.",
"density": "Stored only in this browser.", "density": "이 브라우저에만 저장됩니다.",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "기본으로 표시할 agent 활동 세부 수준을 선택합니다.",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "작은 화면에서도 긴 코드 줄을 읽기 쉽게 유지합니다.",
"maxResults": "Results returned by each web_search call.", "maxResults": "각 web_search 호출에서 반환되는 결과 수입니다.",
"timeout": "Seconds before a search provider request times out.", "timeout": "검색 제공자 요청이 타임아웃되기 전의 초입니다.",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "가능할 때 web_fetch에 Jina Reader를 사용합니다.",
"imageGeneration": "구성된 이미지 제공자를 사용할 수 있을 때 채팅에서 generate_image를 노출합니다.", "imageGeneration": "구성된 이미지 제공자 있을 때 채팅에서 generate_image를 노출합니다.",
"imageProvider": "generate_image가 사용할 레지스트리 제공자를 선택합니다.", "imageProvider": "generate_image에 사용할 등록 제공자를 선택합니다.",
"imageProviderStatus": "이미지 생성은 Providers의 제공자 자격 증명을 재사용합니다.", "imageProviderStatus": "이미지 생성은 제공자 자격 증명을 재사용합니다.",
"imageModel": "선택한 이미지 제공자에 보낼 모델 이름입니다.", "imageModel": "선택한 이미지 제공자에 보낼 모델 이름입니다.",
"defaultAspectRatio": "프롬프트에서 로세로 비율을 선택하지 않을 때 사용됩니다.", "defaultAspectRatio": "프롬프트가 비율을 선택하지 않을 때 사용됩니다.",
"defaultImageSize": "지원하는 제공자에게 보내는 크기 힌트입니다.", "defaultImageSize": "지원하는 제공자에 보낼 크기 힌트입니다.",
"maxImagesPerTurn": "한 번의 generate_image 요청에 대한 상한입니다.", "maxImagesPerTurn": "한 번의 generate_image 요청에서 생성할 수 있는 이미지 상한입니다.",
"botName": "nanobot이 표시 이름을 는 곳에 표시됩니다.", "botName": "nanobot이 표시 이름을 사용하는 곳에 표시됩니다.",
"botIcon": "Bot 이름 옆에 표시할 짧은 emoji 또는 텍스트입니다.", "botIcon": "Bot 이름 옆에 표시할 짧은 emoji 또는 텍스트입니다.",
"timezone": "예약과 시간 인식 답변에 사용됩니다.", "timezone": "일정과 시간 인식 답변에 사용됩니다.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Full Access shell 명령이 localhost 서비스에 접근할 수 있게 합니다.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "프로젝트별 권한이 없는 Web 채팅에 사용됩니다.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "웹 가져오기는 항상 로컬, 사설, 메타데이터 서비스를 보호합니다. 핵심 채널 보안은 config.json에서 관리됩니다.",
"currentModel": "nanobot이 새 답변에 사용할 모델 구성을 선택합니다.", "currentModel": "새 응답에 사용됩니다.",
"selectedModelProvider": "선택한 모델에 설정됩니다.", "selectedModelProvider": "선택한 모델에 의해 설정됩니다.",
"selectedModelValue": "선택한 모델에 설정됩니다.", "selectedModelValue": "선택한 모델에 의해 설정됩니다.",
"brandLogos": "로고는 브랜드 도메인에서 불러오며, 실패하면 로컬 아이콘을 사용합니다.", "brandLogos": "설정에서 타사 제공자와 CLI 로고를 표시합니다.",
"cliAppsCatalog": "nanobot이 로컬에서 실행할 수 있는 앱 CLI를 살펴봅니다.", "cliAppsCatalog": "nanobot이 로컬에서 실행할 수 있는 앱 CLI 어댑터만 설치합니다. 네이티브 앱은 변경하지 않습니다.",
"cliAppsFilter": "앱, 카테고리 또는 기능으로 검색합니다.", "cliAppsFilter": "앱, 카테고리 또는 기능으로 검색합니다.",
"logs": "App 엔진 로그 폴더를 엽니다.", "logs": "네이티브 엔진 로그 폴더를 엽니다.",
"diagnostics": "지원용 작은 런타임 보고서를 내보냅니다.", "diagnostics": "지원용 작은 런타임 보고서를 내보냅니다.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Full Access shell 명령이 이 Mac의 서비스에 접근할 수 있게 합니다.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "프로젝트별 권한이 없는 네이티브 채팅에 사용됩니다.",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "이 모델 구성의 기본 컨텍스트 예산을 선택합니다."
}, },
"values": { "values": {
"light": "라이트", "light": "라이트",
"dark": "다크", "dark": "다크",
"notAvailable": "사용할 수 없음", "notAvailable": "사용 불가",
"enabled": "Enabled", "enabled": "활성화됨",
"disabled": "Disabled", "disabled": "비활성화됨",
"restartPending": "재시작 대기", "restartPending": "재시작 대기",
"ready": "준비됨", "ready": "준비됨",
"comfortable": "Comfortable", "comfortable": "편안함",
"compact": "Compact", "compact": "컴팩트",
"auto": "Auto", "auto": "자동",
"expanded": "Expanded", "expanded": "펼침",
"on": "On", "on": "켜짐",
"off": "Off", "off": "꺼짐",
"defaultPermission": "Default Permission", "defaultPermission": "기본 권한",
"fullAccess": "Full Access", "fullAccess": "전체 접근",
"configured": "Configured", "configured": "구성됨",
"notConfigured": "Not configured", "notConfigured": "미구성",
"pending": "대기 중", "pending": "대기 중",
"restartingEngine": "다시 시작 중" "restartingEngine": "시작 중"
}, },
"status": { "status": {
"loading": "설정을 불러오는 중...", "loading": "설정을 불러오는 중...",
"loadError": "설정을 불러올 수 없습니다", "loadError": "설정을 불러올 수 없습니다",
"unsaved": "저장되지 않은 변경 사항이 있습니다.", "unsaved": "저장되지 않은 변경 사항이 있습니다.",
"upToDate": "최신 상태입니다.", "upToDate": "최신 상태입니다.",
"savedRestart": "저장되었습니다. 적용하려면 nanobot을 재시작하세요.", "savedRestart": "저장습니다. 적용하려면 nanobot을 재시작하세요.",
"restartAfterSaving": "변경 사항을 저장한 뒤 준비되면 재시작하세요.", "restartAfterSaving": "변경 사항을 저장한 뒤 준비되면 재시작하세요.",
"savedRestartApply": "저장되었습니다. 준비되면 재시작하세요.", "savedRestartApply": "저장습니다. 준비되면 재시작하세요.",
"imageProviderRestart": "이미지 제공자 변경 사항이 저장되었습니다. 준비되면 재시작하세요.", "imageProviderRestart": "이미지 제공자 변경 사항을 저장했습니다. 준비되면 재시작하세요.",
"hostRestartAfterSaving": "저장하면 nanobot이 엔진을 다시 시작합니다.", "hostRestartAfterSaving": "저장하면 nanobot이 엔진을 시작합니다.",
"hostRestartPending": "저장되었습니다. 준비되면 엔진을 다시 시작합니다.", "hostRestartPending": "저장했습니다. 준비되면 엔진을 재시작합니다.",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "호스트 작업은 네이티브 앱 안에서만 사용할 수 있습니다.",
"logsOpened": "Opened logs folder.", "logsOpened": "로그 폴더를 열었습니다.",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "로그 폴더를 열 수 없습니다.",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "진단을 {{path}}에 내보냈습니다.",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "진단을 내보낼 수 없습니다."
}, },
"actions": { "actions": {
"save": "저장", "save": "저장",
@ -224,8 +224,8 @@
"cancel": "취소", "cancel": "취소",
"open": "열기", "open": "열기",
"export": "내보내기", "export": "내보내기",
"opening": "Opening...", "opening": "여는 중...",
"exporting": "Exporting..." "exporting": "내보내는 중..."
}, },
"byok": { "byok": {
"description": "직접 provider 키를 가져옵니다. Nanobot은 현재 config에서 값을 읽고, 설정된 provider만 일반 설정에서 선택할 수 있습니다.", "description": "직접 provider 키를 가져옵니다. Nanobot은 현재 config에서 값을 읽고, 설정된 provider만 일반 설정에서 선택할 수 있습니다.",
@ -250,7 +250,7 @@
"tabs": { "tabs": {
"ariaLabel": "BYOK 자격 증명 유형", "ariaLabel": "BYOK 자격 증명 유형",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "웹 검색"
}, },
"webSearch": { "webSearch": {
"provider": "검색 provider", "provider": "검색 provider",
@ -270,17 +270,17 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "현재 모델",
"providers": "Providers", "providers": "제공자",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}}개 구성됨",
"totalProviders": "{{count}} available", "totalProviders": "{{count}}개 사용 가능",
"webSearch": "Web search", "webSearch": "웹 검색",
"imageGeneration": "이미지 생성", "imageGeneration": "이미지 생성",
"workspace": "Workspace" "workspace": "작업공간"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "제공자 검색",
"noMatches": "No providers match this search.", "noMatches": "일치하는 제공자가 없습니다.",
"saveProvider": "제공자 저장" "saveProvider": "제공자 저장"
}, },
"image": { "image": {
@ -294,15 +294,15 @@
"selectModel": "모델 선택", "selectModel": "모델 선택",
"addConfiguration": "구성 추가", "addConfiguration": "구성 추가",
"newConfiguration": "새 모델 구성", "newConfiguration": "새 모델 구성",
"newConfigurationHelp": "제공자와 모델을 한 번에 선택할 수 있는 옵션으로 저장합니다.", "newConfigurationHelp": "제공자와 모델을 원클릭 옵션으로 저장합니다.",
"configurationName": "구성 이름", "configurationName": "구성 이름",
"configurationNameHelp": "저장된 모델 구성의 이름을 변경합니다.", "configurationNameHelp": "저장된 모델 구성의 이름을 변경합니다.",
"configurationNamePlaceholder": "빠른 글쓰기", "configurationNamePlaceholder": "빠른 작성",
"searchModels": "검색하거나 모델 ID 입력", "searchModels": "모델 ID 검색 또는 입력",
"useCustomModel": "사용", "useCustomModel": "사용",
"loadingModels": "모델 불러오는 중...", "loadingModels": "모델 불러오는 중...",
"searchCatalog": "제공자 카탈로그를 검색해 모델을 선택하세요.", "searchCatalog": "제공자 카탈로그에서 모델을 선택합니다.",
"modelsAvailable": "사용 가능", "modelsAvailable": "사용 가능",
"noModelResults": "일치하는 모델이 없습니다.", "noModelResults": "일치하는 모델이 없습니다.",
"loadFailed": "모델 목록을 사용할 수 없습니다.", "loadFailed": "모델 목록을 사용할 수 없습니다.",
"unsupportedModelList": "모델 ID를 직접 입력하세요.", "unsupportedModelList": "모델 ID를 직접 입력하세요.",
@ -402,31 +402,31 @@
"thirdPartyBrands": "제품 이름, 로고 및 브랜드는 각 소유자의 자산입니다. 사용은 식별 목적일 뿐 보증이나 제휴를 의미하지 않습니다." "thirdPartyBrands": "제품 이름, 로고 및 브랜드는 각 소유자의 자산입니다. 사용은 식별 목적일 뿐 보증이나 제휴를 의미하지 않습니다."
}, },
"apps": { "apps": {
"description": "채팅에서 nanobot이 사용할 수 있는 앱 CLI와 MCP 서비스를 추가합니다.", "description": "nanobot이 채팅에서 사용할 수 있는 App CLI와 MCP 서비스를 추가합니다.",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "전체", "filterAll": "전체",
"filterCli": "CLI 앱", "filterCli": "CLI 앱",
"filterMcp": "MCP 서비스", "filterMcp": "MCP 서비스",
"enabledSummary": "{{count}}개 활성화됨", "enabledSummary": "{{count}}개 활성화됨",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "CLI {{cli}}개 · MCP {{mcp}}개",
"searchPlaceholder": "앱 검색", "searchPlaceholder": "앱 검색",
"featured": "추천", "featured": "추천",
"loading": "앱 불러오는 중...", "loading": "앱 불러오는 중...",
"empty": "이 필터와 일치하는 앱이 없습니다." "empty": "일치하는 앱이 없습니다."
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "OAuth 인증",
"signIn": "Sign in", "signIn": "로그인",
"signingIn": "Signing in...", "signingIn": "로그인 중...",
"signInAgain": "Sign in again", "signInAgain": "다시 로그인",
"signOut": "Sign out", "signOut": "로그아웃",
"signedInAs": "Signed in as {{account}}", "signedInAs": "{{account}}로 로그인됨",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "이 기기에서 로그인합니다. API key는 config에 저장되지 않습니다.",
"signInRequired": "Sign in required", "signInRequired": "로그인이 필요합니다",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "이 OAuth 제공자를 활성 모델 제공자로 저장하기 전에 로그인하세요.",
"signedIn": "Signed in", "signedIn": "로그인됨",
"notSignedIn": "Not signed in" "notSignedIn": "로그인 안 됨"
} }
}, },
"chat": { "chat": {

View File

@ -57,22 +57,22 @@
"apps": "Ứng dụng" "apps": "Ứng dụng"
}, },
"settings": { "settings": {
"backToChat": "Quay lại trò chuyện", "backToChat": "Quay lại chat",
"sidebar": { "sidebar": {
"title": "Cài đặt", "title": "Cài đặt",
"ariaLabel": "Các mục cài đặt" "ariaLabel": "Mục cài đặt"
}, },
"nav": { "nav": {
"general": "Chung", "general": "Chung",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "Tổng quan",
"appearance": "Appearance", "appearance": "Giao diện",
"models": "Models", "models": "Mô hình",
"providers": "Providers", "providers": "Nhà cung cấp",
"image": "Image", "image": "Hình ảnh",
"browser": "Web", "browser": "Trang web",
"runtime": "Hệ thống", "runtime": "Hệ thống",
"advanced": "Security", "advanced": "Bảo mật",
"cliApps": "Ứng dụng CLI", "cliApps": "Ứng dụng CLI",
"mcp": "MCP", "mcp": "MCP",
"apps": "Ứng dụng" "apps": "Ứng dụng"
@ -81,122 +81,122 @@
"interface": "Giao diện", "interface": "Giao diện",
"ai": "AI", "ai": "AI",
"system": "Hệ thống", "system": "Hệ thống",
"status": "Status", "status": "Trạng thái",
"localPreferences": "Local preferences", "localPreferences": "Tùy chọn cục bộ",
"presets": "Presets", "presets": "Preset",
"imageGeneration": "Tạo ảnh", "imageGeneration": "Tạo hình ảnh",
"imageDefaults": "Mặc định", "imageDefaults": "Mặc định",
"webSearch": "Web search", "webSearch": "Tìm kiếm web",
"webBehavior": "Behavior", "webBehavior": "Hành vi",
"identity": "Identity", "identity": "Danh tính",
"webuiSafety": "Web safety", "webuiSafety": "An toàn WebUI",
"capabilities": "Khả năng", "capabilities": "Khả năng",
"cliApps": "Ứng dụng CLI", "cliApps": "Ứng dụng CLI",
"mcp": "Dịch vụ MCP", "mcp": "Dịch vụ MCP",
"apps": "Ứng dụng", "apps": "Ứng dụng",
"nativeHost": "Native host", "nativeHost": "Host gốc",
"hostSafety": "App safety" "hostSafety": "An toàn ứng dụng"
}, },
"rows": { "rows": {
"theme": "Giao diện", "theme": "Chủ đề",
"language": "Ngôn ngữ", "language": "Ngôn ngữ",
"provider": "Nhà cung cấp", "provider": "Nhà cung cấp",
"model": "Mô hình", "model": "Mô hình",
"restart": "Khởi động lại nanobot", "restart": "Khởi động lại nanobot",
"configPath": "Đường dẫn cấu hình", "configPath": "Đường dẫn cấu hình",
"activePreset": "Active preset", "activePreset": "Preset đang dùng",
"gateway": "Gateway", "gateway": "Cổng",
"restartState": "Restart state", "restartState": "Trạng thái khởi động lại",
"pendingChanges": "Thay đổi đang chờ", "pendingChanges": "Thay đổi chờ áp dụng",
"selectedPreset": "Selected preset", "selectedPreset": "Preset đã chọn",
"presetModel": "Preset model", "presetModel": "Mô hình preset",
"density": "Density", "density": "Mật độ",
"activityMode": "Activity detail", "activityMode": "Chi tiết hoạt động",
"codeWrap": "Code wrapping", "codeWrap": "Xuống dòng mã",
"maxResults": "Max results", "maxResults": "Kết quả tối đa",
"timeout": "Timeout", "timeout": "Thời gian chờ",
"jinaReader": "Jina reader", "jinaReader": "Trình đọc Jina",
"imageGeneration": "Tạo ảnh", "imageGeneration": "Tạo hình ảnh",
"imageProvider": "Nhà cung cấp ảnh", "imageProvider": "Nhà cung cấp hình ảnh",
"imageProviderStatus": "Trạng thái nhà cung cấp", "imageProviderStatus": "Trạng thái nhà cung cấp",
"imageProviderBase": "Cơ sở nhà cung cấp", "imageProviderBase": "Địa chỉ nhà cung cấp",
"imageModel": "Mô hình ảnh", "imageModel": "Mô hình hình ảnh",
"defaultAspectRatio": "Tỷ lệ mặc định", "defaultAspectRatio": "Tỷ lệ mặc định",
"defaultImageSize": "Kích thước mặc định", "defaultImageSize": "Kích thước mặc định",
"maxImagesPerTurn": "Số ảnh tối đa mỗi lượt", "maxImagesPerTurn": "nh tối đa mỗi lượt",
"imageSaveDir": "Thư mục lưu", "imageSaveDir": "Thư mục lưu",
"botName": "Bot name", "botName": "Tên bot",
"botIcon": "Bot icon", "botIcon": "Biểu tượng bot",
"timezone": "Timezone", "timezone": "Múi giờ",
"workspacePath": "Workspace mặc định", "workspacePath": "Workspace mặc định",
"localServiceAccess": "Local services", "localServiceAccess": "Dịch vụ cục bộ",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "Quyền mặc định",
"currentModel": "Cấu hình hiện tại", "currentModel": "Cấu hình hiện tại",
"brandLogos": "Logo thương hiệu", "brandLogos": "Logo thương hiệu",
"cliAppsCatalog": "Danh mục ứng dụng CLI", "cliAppsCatalog": "Danh mục",
"cliAppsFilter": "Bộ lọc ứng dụng CLI", "cliAppsFilter": "Bộ lọc",
"engine": "Engine", "engine": "Bộ máy",
"logs": "Nhật ký", "logs": "Nhật ký",
"diagnostics": "Chẩn đoán", "diagnostics": "Chẩn đoán",
"contextWindow": "Context window" "contextWindow": "Cửa sổ ngữ cảnh"
}, },
"help": { "help": {
"theme": "Chuyển giữa giao diện sáng và tối.", "theme": "Chuyển giữa giao diện sáng và tối.",
"language": "Chọn ngôn ngữ dùng trong WebUI.", "language": "Chọn ngôn ngữ dùng trong WebUI.",
"provider": "Chọn nhà cung cấp cho các yêu cầu mô hình mới.", "provider": "Selecciona el proveedor para nuevas solicitudes de modelo.",
"model": "Đặt tên mô hình mặc định mà nanobot sử dụng.", "model": "Define el nombre de modelo predeterminado de nanobot.",
"configPath": "Tệp cấu hình gateway hiện đang dùng.", "configPath": "Archivo de configuración que usa actualmente el gateway.",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "Los preajustes con nombre son de solo lectura aquí; edítalos en config.json.",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "Chuyển sang Default để chỉnh sửa mô hình và nhà cung cấp từ WebUI.",
"density": "Stored only in this browser.", "density": "Chỉ lưu trong trình duyệt này.",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "Chọn mức chi tiết hoạt động agent hiển thị mặc định.",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "Giữ các dòng mã dài dễ đọc trên màn hình nhỏ.",
"maxResults": "Results returned by each web_search call.", "maxResults": "Resultados devueltos por cada llamada web_search.",
"timeout": "Seconds before a search provider request times out.", "timeout": "Segundos antes de que una solicitud de búsqueda expire.",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "Usa Jina Reader para web_fetch cuando esté disponible.",
"imageGeneration": "Hiển thị generate_image trong chat khi có nhà cung cấp ảnh đã cấu hình.", "imageGeneration": "Expone generate_image en chats cuando hay un proveedor de imagen configurado.",
"imageProvider": "Chọn nhà cung cấp registry được generate_image sử dụng.", "imageProvider": "Elige el proveedor registrado usado por generate_image.",
"imageProviderStatus": "Tạo ảnh dùng lại thông tin xác thực nhà cung cấp từ Providers.", "imageProviderStatus": "La generación de imágenes reutiliza credenciales de Proveedores.",
"imageModel": "Tên mô hình gửi tới nhà cung cấp ảnh đã chọn.", "imageModel": "Nombre del modelo enviado al proveedor de imágenes seleccionado.",
"defaultAspectRatio": "Được dùng khi prompt không chọn tỷ lệ khung hình.", "defaultAspectRatio": "Se usa cuando el prompt no elige una proporción.",
"defaultImageSize": "Gợi ý kích thước gửi tới các nhà cung cấp hỗ trợ.", "defaultImageSize": "Gợi ý kích thước gửi tới nhà cung cấp hỗ trợ.",
"maxImagesPerTurn": "Giới hạn trên cho một yêu cầu generate_image.", "maxImagesPerTurn": "Giới hạn trên cho một yêu cầu generate_image.",
"botName": "Hiển thị ở nơi nanobot dùng tên hiển thị.", "botName": "Se muestra donde nanobot usa un nombre visible.",
"botIcon": "Emoji hoặc văn bản ngắn hiển thị cùng tên bot.", "botIcon": "Emoji o texto corto junto al nombre del bot.",
"timezone": "Dùng cho lịch hẹn và câu trả lời có yếu tố thời gian.", "timezone": "Se usa para horarios y respuestas con conciencia temporal.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.", "localServiceAccess": "Cho phép lệnh shell Full Access truy cập dịch vụ localhost.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.", "webuiDefaultAccess": "Dùng cho chat web không có quyền riêng theo dự án.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "Las capturas web siempre protegen servicios locales, privados y metadata. La seguridad de canales core se gestiona en config.json.",
"currentModel": "Chọn cấu hình mô hình nanobot dùng cho các câu trả lời mới.", "currentModel": "Dùng cho các phản hồi mới.",
"selectedModelProvider": "Được đặt bởi mô hình đã chọn.", "selectedModelProvider": "Definido por el modelo seleccionado.",
"selectedModelValue": "Được đặt bởi mô hình đã chọn.", "selectedModelValue": "Definido por el modelo seleccionado.",
"brandLogos": "Logo được tải từ tên miền thương hiệu, có biểu tượng cục bộ làm dự phòng.", "brandLogos": "Hiển thị logo nhà cung cấp bên thứ ba và CLI trong Cài đặt.",
"cliAppsCatalog": "Duyệt các CLI ứng dụng mà nanobot có thể chạy cục bộ.", "cliAppsCatalog": "Instala solo adaptadores CLI de apps que nanobot puede ejecutar localmente; las apps nativas no se modifican.",
"cliAppsFilter": "Tìm theo ứng dụng, danh mục hoặc khả năng.", "cliAppsFilter": "Busca por app, categoría o capacidad.",
"logs": "Mở thư mục nhật ký native engine.", "logs": "Abre la carpeta de registros del motor nativo.",
"diagnostics": "Xuất báo cáo runtime nhỏ để hỗ trợ.", "diagnostics": "Exporta un pequeño informe de runtime para soporte.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.", "localServiceAccessNative": "Permite que comandos shell con Full Access alcancen servicios en este Mac.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission.", "webuiDefaultAccessNative": "Usado por chats nativos sin permiso específico de proyecto.",
"contextWindow": "Choose the default context budget for this model configuration." "contextWindow": "Chọn ngân sách ngữ cảnh mặc định cho cấu hình mô hình này."
}, },
"values": { "values": {
"light": "Sáng", "light": "Sáng",
"dark": "Tối", "dark": "Tối",
"notAvailable": "Không khả dụng", "notAvailable": "Không khả dụng",
"enabled": "Enabled", "enabled": "Đã bật",
"disabled": "Disabled", "disabled": "Đã tắt",
"restartPending": "Đang chờ khởi động lại", "restartPending": "Chờ khởi động lại",
"ready": "Sẵn sàng", "ready": "Sẵn sàng",
"comfortable": "Comfortable", "comfortable": "Thoải mái",
"compact": "Compact", "compact": "Gọn",
"auto": "Auto", "auto": "Tự động",
"expanded": "Expanded", "expanded": "Mở rộng",
"on": "On", "on": "Bật",
"off": "Off", "off": "Tắt",
"defaultPermission": "Default Permission", "defaultPermission": "Quyền mặc định",
"fullAccess": "Full Access", "fullAccess": "Toàn quyền",
"configured": "Configured", "configured": "Đã cấu hình",
"notConfigured": "Not configured", "notConfigured": "Chưa cấu hình",
"pending": "Đang chờ", "pending": "Đang chờ",
"restartingEngine": "Đang khởi động lại" "restartingEngine": "Đang khởi động lại"
}, },
@ -205,17 +205,17 @@
"loadError": "Không thể tải cài đặt", "loadError": "Không thể tải cài đặt",
"unsaved": "Có thay đổi chưa lưu.", "unsaved": "Có thay đổi chưa lưu.",
"upToDate": "Đã cập nhật.", "upToDate": "Đã cập nhật.",
"savedRestart": "Đã lưu. Khởi động lại nanobot để áp dụng.", "savedRestart": "Guardado. Reinicia nanobot para aplicar.",
"restartAfterSaving": "Lưu thay đổi, rồi khởi động lại khi sẵn sàng.", "restartAfterSaving": "Guarda los cambios y reinicia cuando puedas.",
"savedRestartApply": "Đã lưu. Khởi động lại khi sẵn sàng.", "savedRestartApply": "Guardado. Reinicia cuando puedas.",
"imageProviderRestart": "Đã lưu thay đổi nhà cung cấp ảnh. Khởi động lại khi sẵn sàng.", "imageProviderRestart": "Cambios del proveedor de imagen guardados. Reinicia cuando puedas.",
"hostRestartAfterSaving": "Lưu thay đổi và nanobot sẽ khởi động lại engine.", "hostRestartAfterSaving": "Al guardar, nanobot reiniciará su motor.",
"hostRestartPending": "Đã lưu. Sẽ khởi động lại engine khi sẵn sàng.", "hostRestartPending": "Guardado. El motor se reiniciará cuando esté listo.",
"hostApiUnavailable": "Host actions are only available inside the native app.", "hostApiUnavailable": "Las acciones del host solo están disponibles en la app nativa.",
"logsOpened": "Opened logs folder.", "logsOpened": "Carpeta de registros abierta.",
"logsOpenFailed": "Could not open logs folder.", "logsOpenFailed": "No se pudo abrir la carpeta de registros.",
"diagnosticsExported": "Diagnostics exported to {{path}}.", "diagnosticsExported": "Diagnóstico exportado a {{path}}.",
"diagnosticsExportFailed": "Could not export diagnostics." "diagnosticsExportFailed": "No se pudo exportar el diagnóstico."
}, },
"actions": { "actions": {
"save": "Lưu", "save": "Lưu",
@ -224,8 +224,8 @@
"cancel": "Hủy", "cancel": "Hủy",
"open": "Mở", "open": "Mở",
"export": "Xuất", "export": "Xuất",
"opening": "Opening...", "opening": "Đang mở...",
"exporting": "Exporting..." "exporting": "Đang xuất..."
}, },
"byok": { "byok": {
"description": "Dùng key provider của riêng bạn. Nanobot đọc các giá trị này từ config hiện tại, và chỉ provider đã cấu hình mới có thể chọn trong Chung.", "description": "Dùng key provider của riêng bạn. Nanobot đọc các giá trị này từ config hiện tại, và chỉ provider đã cấu hình mới có thể chọn trong Chung.",
@ -250,10 +250,10 @@
"tabs": { "tabs": {
"ariaLabel": "Loại thông tin xác thực BYOK", "ariaLabel": "Loại thông tin xác thực BYOK",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "Tìm kiếm web"
}, },
"webSearch": { "webSearch": {
"provider": "Search provider", "provider": "Nhà cung cấp tìm kiếm",
"providerHelp": "Chọn backend mà công cụ web search sẽ dùng.", "providerHelp": "Chọn backend mà công cụ web search sẽ dùng.",
"selectProvider": "Chọn provider", "selectProvider": "Chọn provider",
"credentials": "Thông tin xác thực", "credentials": "Thông tin xác thực",
@ -270,17 +270,17 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "Mô hình hiện tại",
"providers": "Providers", "providers": "Nhà cung cấp",
"configuredCount": "{{count}} configured", "configuredCount": "{{count}} đã cấu hình",
"totalProviders": "{{count}} available", "totalProviders": "{{count}} khả dụng",
"webSearch": "Web search", "webSearch": "Tìm kiếm web",
"imageGeneration": "Tạo ảnh", "imageGeneration": "Tạo hình ảnh",
"workspace": "Workspace" "workspace": "Không gian làm việc"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "Tìm nhà cung cấp",
"noMatches": "No providers match this search.", "noMatches": "Không có nhà cung cấp phù hợp.",
"saveProvider": "Lưu nhà cung cấp" "saveProvider": "Lưu nhà cung cấp"
}, },
"image": { "image": {
@ -288,17 +288,17 @@
"selectAspect": "Chọn tỷ lệ", "selectAspect": "Chọn tỷ lệ",
"selectSize": "Chọn kích thước", "selectSize": "Chọn kích thước",
"configureProvider": "Cấu hình nhà cung cấp", "configureProvider": "Cấu hình nhà cung cấp",
"missingCredential": "Cấu hình nhà cung cấp này trước khi bật tạo ảnh." "missingCredential": "Configura este proveedor antes de activar la generación de imágenes."
}, },
"models": { "models": {
"selectModel": "Chọn mô hình", "selectModel": "Chọn mô hình",
"addConfiguration": "Thêm cấu hình", "addConfiguration": "Thêm cấu hình",
"newConfiguration": "Cấu hình mô hình mới", "newConfiguration": "Cấu hình mô hình mới",
"newConfigurationHelp": "Lưu nhà cung cấp và mô hình thành một lựa chọn một lần nhấp.", "newConfigurationHelp": "Lưu nhà cung cấp và mô hình thành một lựa chọn nhanh.",
"configurationName": "Tên cấu hình", "configurationName": "Tên cấu hình",
"configurationNameHelp": "Đổi tên cấu hình mô hình đã lưu này.", "configurationNameHelp": "Đổi tên cấu hình mô hình đã lưu này.",
"configurationNamePlaceholder": "Viết nhanh", "configurationNamePlaceholder": "Viết nhanh",
"searchModels": "Tìm hoặc nhập ID mô hình", "searchModels": "Tìm kiếm hoặc nhập ID mô hình",
"useCustomModel": "Dùng", "useCustomModel": "Dùng",
"loadingModels": "Đang tải mô hình...", "loadingModels": "Đang tải mô hình...",
"searchCatalog": "Tìm trong danh mục nhà cung cấp để chọn mô hình.", "searchCatalog": "Tìm trong danh mục nhà cung cấp để chọn mô hình.",
@ -306,7 +306,7 @@
"noModelResults": "Không có mô hình phù hợp.", "noModelResults": "Không có mô hình phù hợp.",
"loadFailed": "Không tải được danh sách mô hình.", "loadFailed": "Không tải được danh sách mô hình.",
"unsupportedModelList": "Nhập ID mô hình thủ công.", "unsupportedModelList": "Nhập ID mô hình thủ công.",
"providerNotConfigured": "Cấu hình nhà cung cấp này trước khi tải mô hình.", "providerNotConfigured": "Hãy cấu hình nhà cung cấp này trước khi tải mô hình.",
"autoProviderCustomOnly": "Chế độ nhà cung cấp tự động dùng ID mô hình tùy chỉnh." "autoProviderCustomOnly": "Chế độ nhà cung cấp tự động dùng ID mô hình tùy chỉnh."
}, },
"timezone": { "timezone": {
@ -402,7 +402,7 @@
"thirdPartyBrands": "Tên sản phẩm, logo và thương hiệu thuộc về chủ sở hữu tương ứng. Việc sử dụng chỉ nhằm nhận diện và không ngụ ý được xác nhận." "thirdPartyBrands": "Tên sản phẩm, logo và thương hiệu thuộc về chủ sở hữu tương ứng. Việc sử dụng chỉ nhằm nhận diện và không ngụ ý được xác nhận."
}, },
"apps": { "apps": {
"description": "Thêm CLI ứng dụng và dịch vụ MCP để nanobot dùng trong trò chuyện.", "description": "Thêm CLI ứng dụng và dịch vụ MCP mà nanobot có thể dùng trong chat.",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "Tất cả", "filterAll": "Tất cả",
@ -413,20 +413,20 @@
"searchPlaceholder": "Tìm ứng dụng", "searchPlaceholder": "Tìm ứng dụng",
"featured": "Nổi bật", "featured": "Nổi bật",
"loading": "Đang tải ứng dụng...", "loading": "Đang tải ứng dụng...",
"empty": "Không có ứng dụng nào khớp với bộ lọc này." "empty": "Không có ứng dụng phù hợp."
}, },
"oauth": { "oauth": {
"authentication": "OAuth authentication", "authentication": "Xác thực OAuth",
"signIn": "Sign in", "signIn": "Đăng nhập",
"signingIn": "Signing in...", "signingIn": "Đang đăng nhập...",
"signInAgain": "Sign in again", "signInAgain": "Đăng nhập lại",
"signOut": "Sign out", "signOut": "Đăng xuất",
"signedInAs": "Signed in as {{account}}", "signedInAs": "Đã đăng nhập bằng {{account}}",
"signInHelp": "Sign in from this device; no API key is stored in config.", "signInHelp": "Inicia sesión desde este dispositivo; no se guarda API key en config.",
"signInRequired": "Sign in required", "signInRequired": "Cần đăng nhập",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.", "signInBeforeSaving": "Inicia sesión antes de guardar este proveedor OAuth como proveedor activo.",
"signedIn": "Signed in", "signedIn": "Đã đăng nhập",
"notSignedIn": "Not signed in" "notSignedIn": "Chưa đăng nhập"
} }
}, },
"chat": { "chat": {

View File

@ -57,7 +57,7 @@
"apps": "应用" "apps": "应用"
}, },
"settings": { "settings": {
"backToChat": "返回对话", "backToChat": "返回聊天",
"sidebar": { "sidebar": {
"title": "设置", "title": "设置",
"ariaLabel": "设置分区" "ariaLabel": "设置分区"
@ -91,30 +91,30 @@
"cliApps": "CLI 应用", "cliApps": "CLI 应用",
"mcp": "MCP 服务", "mcp": "MCP 服务",
"identity": "身份", "identity": "身份",
"webuiSafety": "网页端安全", "webuiSafety": "WebUI 安全",
"capabilities": "能力", "capabilities": "能力",
"apps": "应用", "apps": "应用",
"nativeHost": "App", "nativeHost": "原生宿主",
"hostSafety": "App 安全" "hostSafety": "应用安全"
}, },
"models": { "models": {
"selectModel": "选择模型", "selectModel": "选择模型",
"addConfiguration": "添加配置", "addConfiguration": "添加配置",
"newConfiguration": "新建模型配置", "newConfiguration": "新建模型配置",
"newConfigurationHelp": "把服务商和模型保存为一个可直接切换的选项。", "newConfigurationHelp": "把提供商和模型保存成一键选项。",
"configurationName": "配置名称", "configurationName": "配置名称",
"configurationNameHelp": "重命名这个已保存的模型配置。", "configurationNameHelp": "重命名这个已保存的模型配置。",
"configurationNamePlaceholder": "快速写作", "configurationNamePlaceholder": "快速写作",
"searchModels": "搜索或输入模型 ID", "searchModels": "搜索或输入模型 ID",
"useCustomModel": "使用", "useCustomModel": "使用",
"loadingModels": "正在加载模型...", "loadingModels": "正在加载模型...",
"searchCatalog": "搜索服务商目录来选择模型。", "searchCatalog": "搜索提供商目录来选择模型。",
"modelsAvailable": "可用", "modelsAvailable": "可用",
"noModelResults": "没有匹配的模型。", "noModelResults": "没有匹配的模型。",
"loadFailed": "模型列表不可用。", "loadFailed": "模型列表不可用。",
"unsupportedModelList": "手动输入模型 ID。", "unsupportedModelList": "手动输入模型 ID。",
"providerNotConfigured": "先配置这个服务商再加载模型。", "providerNotConfigured": "加载模型前请先配置此提供商。",
"autoProviderCustomOnly": "自动服务商模式使用自定义模型 ID。" "autoProviderCustomOnly": "自动提供商模式使用自定义模型 ID。"
}, },
"rows": { "rows": {
"theme": "主题", "theme": "主题",
@ -126,25 +126,25 @@
"activePreset": "当前预设", "activePreset": "当前预设",
"gateway": "网关", "gateway": "网关",
"restartState": "重启状态", "restartState": "重启状态",
"pendingChanges": "待处理更改", "pendingChanges": "待应用更改",
"currentModel": "当前配置", "currentModel": "当前配置",
"selectedPreset": "选中的预设", "selectedPreset": "选中的预设",
"presetModel": "预设模型", "presetModel": "预设模型",
"density": "密度", "density": "密度",
"activityMode": "活动细节", "activityMode": "活动详情",
"codeWrap": "代码换行", "codeWrap": "代码换行",
"brandLogos": "品牌 Logo", "brandLogos": "品牌 Logo",
"maxResults": "最大结果数", "maxResults": "最大结果数",
"timeout": "超时", "timeout": "超时",
"jinaReader": "Jina Reader", "jinaReader": "Jina 阅读器",
"imageGeneration": "图片生成", "imageGeneration": "图片生成",
"imageProvider": "图片服务商", "imageProvider": "图片提供商",
"imageProviderStatus": "服务商状态", "imageProviderStatus": "提供商状态",
"imageProviderBase": "服务商地址", "imageProviderBase": "提供商地址",
"imageModel": "图片模型", "imageModel": "图片模型",
"defaultAspectRatio": "默认比例", "defaultAspectRatio": "默认比例",
"defaultImageSize": "默认尺寸", "defaultImageSize": "默认尺寸",
"maxImagesPerTurn": "每轮最图片数", "maxImagesPerTurn": "每轮最图片数",
"imageSaveDir": "保存目录", "imageSaveDir": "保存目录",
"botName": "Bot 名称", "botName": "Bot 名称",
"botIcon": "Bot 图标", "botIcon": "Bot 图标",
@ -162,41 +162,41 @@
"help": { "help": {
"theme": "在浅色和深色外观之间切换。", "theme": "在浅色和深色外观之间切换。",
"language": "选择 WebUI 使用的语言。", "language": "选择 WebUI 使用的语言。",
"provider": "选择新模型请求使用的服务商。", "provider": "选择处理新模型请求的提供商。",
"model": "设置 nanobot 默认使用的模型名称。", "model": "设置 nanobot 默认使用的模型名称。",
"configPath": "当前网关正在使用的配置文件。", "configPath": "当前网关正在使用的配置文件。",
"currentModel": "选择 nanobot 接下来回复时使用的模型配置。", "currentModel": "用于新的回复。",
"selectedModelProvider": "由当前模型决定。", "selectedModelProvider": "由选中的模型决定。",
"selectedModelValue": "由当前模型决定。", "selectedModelValue": "由选中的模型决定。",
"selectedPreset": "命名预设在这里只读;需要编辑时请改 config.json。", "selectedPreset": "命名预设在这里只读;请在 config.json 中编辑。",
"presetModel": "切回 Default 后可在 WebUI 编辑模型和服务商。", "presetModel": "切回 Default 后可在 WebUI 中编辑模型和提供商。",
"density": "仅保存在当前浏览器。", "density": "只保存在此浏览器中。",
"activityMode": "选择默认显示多少 agent 活动细节。", "activityMode": "选择默认显示多少 agent 活动细节。",
"codeWrap": "让较小屏幕上的长代码行更易读。", "codeWrap": "让长代码行在小屏幕上也易读。",
"brandLogos": "在设置页显示第三方服务商和 CLI 的 Logo。", "brandLogos": "在设置中显示第三方提供商和 CLI 图标。",
"maxResults": "每次 web_search 返回的结果数。", "maxResults": "每次 web_search 调用返回的结果数。",
"timeout": "搜索服务商请求超时秒数。", "timeout": "搜索提供商请求超时前的秒数。",
"jinaReader": "可用时为 web_fetch 使用 Jina Reader。", "jinaReader": "可用时为 web_fetch 使用 Jina Reader。",
"imageGeneration": "当已配置图片服务商时,在对话中开放 generate_image。", "imageGeneration": "配置图片提供商后,在聊天中开放 generate_image。",
"imageProvider": "选择 generate_image 使用的服务商。", "imageProvider": "选择 generate_image 使用的注册提供商。",
"imageProviderStatus": "图片生成复用服务商页里的凭证配置。", "imageProviderStatus": "图片生成会复用「提供商」里的凭据。",
"imageModel": "发送给所选图片服务商的模型名称。", "imageModel": "发送给所选图片提供商的模型名称。",
"defaultAspectRatio": "当提示词没有选择比例时使用。", "defaultAspectRatio": "当提示词没有指定比例时使用。",
"defaultImageSize": "发送给支持该能力的服务商的尺寸提示。", "defaultImageSize": "发送给支持此选项的提供商的尺寸提示。",
"maxImagesPerTurn": "单次 generate_image 请求允许的图片上限。", "maxImagesPerTurn": "单次 generate_image 请求可生成的图片上限。",
"botName": "显示在 nanobot 使用名称的地方。", "botName": "显示在 nanobot 使用展示名称的地方。",
"botIcon": "显示在 bot 名称旁的短 emoji 或文本。", "botIcon": "显示在 Bot 名称旁的短 emoji 或文字。",
"timezone": "用于计划任务和需要时间感知的回复。", "timezone": "用于日程和需要时间感知的回复。",
"cliAppsCatalog": "只安装 nanobot 在本机调用应用时需要的 CLI 适配层,不触碰应用本体。", "cliAppsCatalog": "只安装 nanobot 可本地运行的应用 CLI 适配器;不会改动原生应用。",
"cliAppsFilter": "按应用、类或能力搜索。", "cliAppsFilter": "按应用、或能力搜索。",
"localServiceAccess": "允许完全访问模式下的 shell 命令访问 localhost 服务。", "localServiceAccess": "允许完全访问权限下的 shell 命令访问 localhost 服务。",
"webuiDefaultAccess": "用于没有单独选择权限的网页端对话。", "webuiDefaultAccess": "用于没有单独项目权限的 Web 聊天。",
"securityManagedControls": "网页抓取始终保护本机、内网和元数据服务。核心渠道安全仍由 config.json 管理。", "securityManagedControls": "网页抓取始终保护本机、内网和元数据服务。核心渠道安全仍由 config.json 管理。",
"logs": "打开App引擎日志文件夹。", "logs": "打开原生引擎日志文件夹。",
"diagnostics": "导出一份用于支持排查的运行报告。", "diagnostics": "导出一份用于支持排查的小型运行报告。",
"localServiceAccessNative": "允许完全访问模式下的 shell 命令访问这台 Mac 上的服务。", "localServiceAccessNative": "允许完全访问权限下的 shell 命令访问这台 Mac 上的服务。",
"webuiDefaultAccessNative": "用于没有单独选择权限的原生 App 对话。", "webuiDefaultAccessNative": "用于没有单独项目权限的原生聊天。",
"contextWindow": "选择这个模型配置默认使用的上下文预算。" "contextWindow": "选择此模型配置的默认上下文预算。"
}, },
"timezone": { "timezone": {
"select": "选择时区", "select": "选择时区",
@ -251,9 +251,9 @@
"serverUrl": "URL", "serverUrl": "URL",
"transport": "传输方式", "transport": "传输方式",
"command": "命令", "command": "命令",
"args": "参数 JSON", "args": "Args JSON",
"headers": "Headers JSON", "headers": "Headers JSON",
"env": "环境变量 JSON", "env": "Env JSON",
"timeout": "工具超时", "timeout": "工具超时",
"advancedOptions": "高级选项", "advancedOptions": "高级选项",
"hideAdvanced": "收起高级", "hideAdvanced": "收起高级",
@ -299,13 +299,13 @@
"compact": "紧凑", "compact": "紧凑",
"auto": "自动", "auto": "自动",
"expanded": "展开", "expanded": "展开",
"on": "开", "on": "开",
"off": "关", "off": "关",
"defaultPermission": "默认权限", "defaultPermission": "默认权限",
"fullAccess": "完全访问", "fullAccess": "完全访问权限",
"configured": "已配置", "configured": "已配置",
"notConfigured": "未配置", "notConfigured": "未配置",
"pending": "待应用", "pending": "等待中",
"restartingEngine": "正在重启" "restartingEngine": "正在重启"
}, },
"status": { "status": {
@ -314,12 +314,12 @@
"unsaved": "有未保存的更改。", "unsaved": "有未保存的更改。",
"upToDate": "已是最新。", "upToDate": "已是最新。",
"savedRestart": "已保存。重启 nanobot 后生效。", "savedRestart": "已保存。重启 nanobot 后生效。",
"restartAfterSaving": "保存后,在合适时重启。", "restartAfterSaving": "保存更改后,在合适时重启。",
"savedRestartApply": "已保存,可稍后重启。", "savedRestartApply": "已保存。准备好后重启。",
"imageProviderRestart": "图片服务商改动已保存,可稍后重启。", "imageProviderRestart": "图片提供商更改已保存。准备好后重启。",
"hostRestartAfterSaving": "保存后nanobot 会自动重启引擎。", "hostRestartAfterSaving": "保存后 nanobot 会重启引擎。",
"hostRestartPending": "已保存,将在合适时重启引擎。", "hostRestartPending": "已保存。准备好后会重启引擎。",
"hostApiUnavailable": "宿主操作只能在原生 App 内使用。", "hostApiUnavailable": "宿主操作仅在原生应用中可用。",
"logsOpened": "已打开日志文件夹。", "logsOpened": "已打开日志文件夹。",
"logsOpenFailed": "无法打开日志文件夹。", "logsOpenFailed": "无法打开日志文件夹。",
"diagnosticsExported": "诊断已导出到 {{path}}。", "diagnosticsExported": "诊断已导出到 {{path}}。",
@ -327,13 +327,13 @@
}, },
"actions": { "actions": {
"save": "保存", "save": "保存",
"saving": "保存", "saving": "正在保存",
"edit": "编辑", "edit": "编辑",
"cancel": "取消", "cancel": "取消",
"open": "打开", "open": "打开",
"export": "导出", "export": "导出",
"opening": "打开...", "opening": "正在打开...",
"exporting": "导出..." "exporting": "正在导出..."
}, },
"byok": { "byok": {
"description": "自带服务商密钥。Nanobot 会从当前 config 读取这些值,只有已配置的服务商才能在通用设置里选择。", "description": "自带服务商密钥。Nanobot 会从当前 config 读取这些值,只有已配置的服务商才能在通用设置里选择。",
@ -387,19 +387,19 @@
"workspace": "工作区" "workspace": "工作区"
}, },
"providers": { "providers": {
"searchPlaceholder": "搜索服务商", "searchPlaceholder": "搜索提供商",
"noMatches": "没有匹配的服务商。", "noMatches": "没有匹配的提供商。",
"saveProvider": "保存服务商" "saveProvider": "保存提供商"
}, },
"legal": { "legal": {
"thirdPartyBrands": "产品名称、Logo 和品牌归各自所有者所有;此处仅用于识别,不代表背书或合作。" "thirdPartyBrands": "产品名称、Logo 和品牌归各自所有者所有;此处仅用于识别,不代表背书或合作。"
}, },
"image": { "image": {
"selectProvider": "选择服务商", "selectProvider": "选择提供商",
"selectAspect": "选择比例", "selectAspect": "选择比例",
"selectSize": "选择尺寸", "selectSize": "选择尺寸",
"configureProvider": "配置服务商", "configureProvider": "配置提供商",
"missingCredential": "启用图片生成前,请先配置这个服务商。" "missingCredential": "启用图片生成前请先配置此提供商。"
}, },
"apps": { "apps": {
"description": "添加 nanobot 可在聊天中使用的 App CLI 和 MCP 服务。", "description": "添加 nanobot 可在聊天中使用的 App CLI 和 MCP 服务。",
@ -409,22 +409,22 @@
"filterCli": "CLI 应用", "filterCli": "CLI 应用",
"filterMcp": "MCP 服务", "filterMcp": "MCP 服务",
"enabledSummary": "已启用 {{count}} 个", "enabledSummary": "已启用 {{count}} 个",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "{{cli}} CLI · {{mcp}} MCP",
"searchPlaceholder": "搜索应用", "searchPlaceholder": "搜索应用",
"featured": "精选", "featured": "精选",
"loading": "正在加载应用...", "loading": "正在加载应用...",
"empty": "没有符合筛选条件的应用。" "empty": "没有匹配的应用。"
}, },
"oauth": { "oauth": {
"authentication": "OAuth 认证", "authentication": "OAuth 认证",
"signIn": "登录", "signIn": "登录",
"signingIn": "正在登录…", "signingIn": "登录中...",
"signInAgain": "重新登录", "signInAgain": "重新登录",
"signOut": "退出登录", "signOut": "退出登录",
"signedInAs": "已登录为 {{account}}", "signedInAs": "已登录为 {{account}}",
"signInHelp": "在这台设备上登录;不会把 API key 写入配置。", "signInHelp": "从这台设备登录;不会在配置中保存 API key。",
"signInRequired": "需要登录", "signInRequired": "需要登录",
"signInBeforeSaving": "先登录这个 OAuth 提供商,然后再保存为当前模型提供商。", "signInBeforeSaving": "将此 OAuth 提供商设为当前模型提供商前,请先登录。",
"signedIn": "已登录", "signedIn": "已登录",
"notSignedIn": "未登录" "notSignedIn": "未登录"
} }

View File

@ -57,7 +57,7 @@
"apps": "應用" "apps": "應用"
}, },
"settings": { "settings": {
"backToChat": "返回對話", "backToChat": "返回聊天",
"sidebar": { "sidebar": {
"title": "設定", "title": "設定",
"ariaLabel": "設定分區" "ariaLabel": "設定分區"
@ -65,14 +65,14 @@
"nav": { "nav": {
"general": "一般", "general": "一般",
"byok": "BYOK", "byok": "BYOK",
"overview": "Overview", "overview": "概覽",
"appearance": "Appearance", "appearance": "外觀",
"models": "Models", "models": "模型",
"providers": "Providers", "providers": "提供商",
"image": "Image", "image": "圖片",
"browser": "Web", "browser": "網頁",
"runtime": "系統", "runtime": "系統",
"advanced": "Security", "advanced": "安全",
"cliApps": "CLI 應用", "cliApps": "CLI 應用",
"mcp": "MCP", "mcp": "MCP",
"apps": "應用" "apps": "應用"
@ -81,60 +81,60 @@
"interface": "介面", "interface": "介面",
"ai": "AI", "ai": "AI",
"system": "系統", "system": "系統",
"status": "Status", "status": "狀態",
"localPreferences": "Local preferences", "localPreferences": "本機偏好",
"presets": "Presets", "presets": "預設",
"imageGeneration": "圖片生成", "imageGeneration": "圖片生成",
"imageDefaults": "預設值", "imageDefaults": "預設值",
"webSearch": "Web search", "webSearch": "網頁搜尋",
"webBehavior": "Behavior", "webBehavior": "行為",
"identity": "Identity", "identity": "身分",
"webuiSafety": "網頁端安全", "webuiSafety": "WebUI 安全",
"capabilities": "能", "capabilities": "",
"cliApps": "CLI 應用", "cliApps": "CLI 應用",
"mcp": "MCP 服務", "mcp": "MCP 服務",
"apps": "應用", "apps": "應用",
"nativeHost": "App", "nativeHost": "原生宿主",
"hostSafety": "App 安全" "hostSafety": "App 安全"
}, },
"rows": { "rows": {
"theme": "主題", "theme": "主題",
"language": "語言", "language": "語言",
"provider": "提供者", "provider": "供應商",
"model": "模型", "model": "模型",
"restart": "重新啟動 nanobot", "restart": "重新啟動 nanobot",
"configPath": "設定檔路徑", "configPath": "配置路徑",
"activePreset": "Active preset", "activePreset": "目前預設",
"gateway": "Gateway", "gateway": "閘道",
"restartState": "Restart state", "restartState": "重啟狀態",
"pendingChanges": "待處理變更", "pendingChanges": "待套用更改",
"selectedPreset": "Selected preset", "selectedPreset": "已選預設",
"presetModel": "Preset model", "presetModel": "預設模型",
"density": "Density", "density": "密度",
"activityMode": "Activity detail", "activityMode": "活動細節",
"codeWrap": "Code wrapping", "codeWrap": "程式碼換行",
"maxResults": "Max results", "maxResults": "最大結果數",
"timeout": "Timeout", "timeout": "逾時",
"jinaReader": "Jina reader", "jinaReader": "Jina 閱讀器",
"imageGeneration": "圖片生成", "imageGeneration": "圖片生成",
"imageProvider": "圖片服務商", "imageProvider": "圖片供應商",
"imageProviderStatus": "服務商狀態", "imageProviderStatus": "供應商狀態",
"imageProviderBase": "服務商位址", "imageProviderBase": "供應商位址",
"imageModel": "圖片模型", "imageModel": "圖片模型",
"defaultAspectRatio": "預設比例", "defaultAspectRatio": "預設比例",
"defaultImageSize": "預設尺寸", "defaultImageSize": "預設尺寸",
"maxImagesPerTurn": "每輪最圖片數", "maxImagesPerTurn": "每輪最圖片數",
"imageSaveDir": "儲存目錄", "imageSaveDir": "儲存目錄",
"botName": "Bot name", "botName": "Bot 名稱",
"botIcon": "Bot icon", "botIcon": "Bot 圖示",
"timezone": "Timezone", "timezone": "時區",
"workspacePath": "預設工作區", "workspacePath": "預設工作區",
"localServiceAccess": "Local services", "localServiceAccess": "本機服務",
"webuiDefaultAccess": "Default access", "webuiDefaultAccess": "預設權限",
"currentModel": "目前設定", "currentModel": "目前設定",
"brandLogos": "品牌標誌", "brandLogos": "品牌 Logo",
"cliAppsCatalog": "CLI 應用目錄", "cliAppsCatalog": "目錄",
"cliAppsFilter": "CLI 應用篩選", "cliAppsFilter": "篩選",
"engine": "引擎", "engine": "引擎",
"logs": "日誌", "logs": "日誌",
"diagnostics": "診斷", "diagnostics": "診斷",
@ -143,75 +143,75 @@
"help": { "help": {
"theme": "在淺色與深色外觀之間切換。", "theme": "在淺色與深色外觀之間切換。",
"language": "選擇 WebUI 使用的語言。", "language": "選擇 WebUI 使用的語言。",
"provider": "選擇新模型請求使用的服務提供者。", "provider": "選擇處理新模型請求的供應商。",
"model": "設定 nanobot 預設使用的模型名稱。", "model": "設定 nanobot 預設使用的模型名稱。",
"configPath": "目前閘道正在使用的設定檔。", "configPath": "目前閘道使用中的配置檔。",
"selectedPreset": "Named presets are read-only here; edit them in config.json.", "selectedPreset": "命名預設在此為唯讀;請在 config.json 中編輯。",
"presetModel": "Switch to Default to edit model and provider from the WebUI.", "presetModel": "切回 Default 後可在 WebUI 中編輯模型與供應商。",
"density": "Stored only in this browser.", "density": "只儲存在此瀏覽器中。",
"activityMode": "Choose how much agent activity chrome to show by default.", "activityMode": "選擇預設顯示多少 agent 活動細節。",
"codeWrap": "Keep long code lines readable on smaller screens.", "codeWrap": "讓長程式碼行在小螢幕上也易讀。",
"maxResults": "Results returned by each web_search call.", "maxResults": "每次 web_search 呼叫返回的結果數。",
"timeout": "Seconds before a search provider request times out.", "timeout": "搜尋供應商請求逾時前的秒數。",
"jinaReader": "Use Jina Reader for web_fetch when available.", "jinaReader": "可用時為 web_fetch 使用 Jina Reader。",
"imageGeneration": "當已設定圖片服務商時,在對話中開放 generate_image。", "imageGeneration": "配置圖片供應商後,在聊天中開放 generate_image。",
"imageProvider": "選擇 generate_image 使用的登錄服務商。", "imageProvider": "選擇 generate_image 使用的註冊供應商。",
"imageProviderStatus": "圖片生成會重用「服務商」中的憑證。", "imageProviderStatus": "圖片生成會重用「供應商」中的憑證。",
"imageModel": "傳送給所選圖片服務商的模型名稱。", "imageModel": "傳送給所選圖片供應商的模型名稱。",
"defaultAspectRatio": "提示詞未指定長寬比時使用。", "defaultAspectRatio": "提示詞未指定比時使用。",
"defaultImageSize": "傳送給支援此功能的服務商的尺寸提示。", "defaultImageSize": "傳送給支援此選項的供應商的尺寸提示。",
"maxImagesPerTurn": "單次 generate_image 請求的上限。", "maxImagesPerTurn": "單次 generate_image 請求可生成圖片上限。",
"botName": "顯示在 nanobot 使用名稱的地方。", "botName": "顯示在 nanobot 使用顯示名稱的位置。",
"botIcon": "顯示在 bot 名稱旁的短 emoji 或文字。", "botIcon": "顯示在 Bot 名稱旁的短 emoji 或文字。",
"timezone": "用於排程需要時間感知的回覆。", "timezone": "用於排程需要時間感知的回覆。",
"localServiceAccess": "允許完全存取模式下的 shell 命令存取 localhost 服務。", "localServiceAccess": "允許完全訪問權限下的 shell 命令訪問 localhost 服務。",
"webuiDefaultAccess": "用於沒有單獨選擇權限的網頁端對話。", "webuiDefaultAccess": "用於沒有單獨專案權限的 Web 聊天。",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.", "securityManagedControls": "網頁抓取始終保護本機、內網和 metadata 服務。核心渠道安全仍由 config.json 管理。",
"currentModel": "選擇 nanobot 接下來回覆時使用的模型設定。", "currentModel": "用於新的回覆。",
"selectedModelProvider": "由目前模型決定。", "selectedModelProvider": "由選取的模型決定。",
"selectedModelValue": "由目前模型決定。", "selectedModelValue": "由選取的模型決定。",
"brandLogos": "標誌會從品牌網域載入,並提供本地圖示作為備援。", "brandLogos": "在設定中顯示第三方提供商和 CLI 圖示。",
"cliAppsCatalog": "瀏覽 nanobot 可在本機執行的應用 CLI。", "cliAppsCatalog": "只安裝 nanobot 可在本機執行的應用 CLI 轉接器;不會改動原生應用。",
"cliAppsFilter": "按應用、類或能力搜尋。", "cliAppsFilter": "按應用、或能力搜尋。",
"logs": "開啟App引擎日誌資料夾。", "logs": "開啟原生引擎日誌資料夾。",
"diagnostics": "匯出一份供支援排查用的執行階段報告。", "diagnostics": "匯出一份用於支援排查的小型執行報告。",
"localServiceAccessNative": "允許完全存取模式下的 shell 命令存取這台 Mac 上的服務。", "localServiceAccessNative": "允許完全訪問權限下的 shell 命令訪問這台 Mac 上的服務。",
"webuiDefaultAccessNative": "用於沒有單獨選擇權限的原生 App 對話。", "webuiDefaultAccessNative": "用於沒有單獨專案權限的原生聊天。",
"contextWindow": "選擇這個模型設定預設使用的上下文預算。" "contextWindow": "選擇此模型配置的預設上下文預算。"
}, },
"values": { "values": {
"light": "淺色", "light": "淺色",
"dark": "深色", "dark": "深色",
"notAvailable": "不可用", "notAvailable": "不可用",
"enabled": "Enabled", "enabled": "已啟用",
"disabled": "Disabled", "disabled": "已停用",
"restartPending": "等待重", "restartPending": "等待重啟",
"ready": "就緒", "ready": "就緒",
"comfortable": "Comfortable", "comfortable": "舒適",
"compact": "Compact", "compact": "緊湊",
"auto": "Auto", "auto": "自動",
"expanded": "Expanded", "expanded": "展開",
"on": "On", "on": "開啟",
"off": "Off", "off": "關閉",
"defaultPermission": "Default Permission", "defaultPermission": "預設權限",
"fullAccess": "Full Access", "fullAccess": "完全訪問權限",
"configured": "Configured", "configured": "已配置",
"notConfigured": "Not configured", "notConfigured": "未配置",
"pending": "待套用", "pending": "等待中",
"restartingEngine": "正在重" "restartingEngine": "正在重啟"
}, },
"status": { "status": {
"loading": "正在載入設定...", "loading": "正在載入設定...",
"loadError": "無法載入設定", "loadError": "無法載入設定",
"unsaved": "有未儲存的更。", "unsaved": "有未儲存的。",
"upToDate": "已是最新。", "upToDate": "已是最新。",
"savedRestart": "已儲存。重新啟動 nanobot 後生效。", "savedRestart": "已儲存。重新啟動 nanobot 後生效。",
"restartAfterSaving": "儲存變更後,可在準備好時重新啟動。", "restartAfterSaving": "儲存更改後,在合適時重啟。",
"savedRestartApply": "已儲存,可在準備好時重新啟動。", "savedRestartApply": "已儲存。準備好後重啟。",
"imageProviderRestart": "圖片服務商變更已儲存,可在準備好時重新啟動。", "imageProviderRestart": "圖片供應商更改已儲存。準備好後重啟。",
"hostRestartAfterSaving": "儲存後nanobot 會自動重新啟動引擎。", "hostRestartAfterSaving": "儲存後 nanobot 會重啟引擎。",
"hostRestartPending": "已儲存,將在適當時重新啟動引擎。", "hostRestartPending": "已儲存。準備好後會重啟引擎。",
"hostApiUnavailable": "宿主操作只能在原生 App 內使用。", "hostApiUnavailable": "宿主操作僅在原生應用中可用。",
"logsOpened": "已開啟日誌資料夾。", "logsOpened": "已開啟日誌資料夾。",
"logsOpenFailed": "無法開啟日誌資料夾。", "logsOpenFailed": "無法開啟日誌資料夾。",
"diagnosticsExported": "診斷已匯出到 {{path}}。", "diagnosticsExported": "診斷已匯出到 {{path}}。",
@ -219,13 +219,13 @@
}, },
"actions": { "actions": {
"save": "儲存", "save": "儲存",
"saving": "儲存", "saving": "正在儲存",
"edit": "編輯", "edit": "編輯",
"cancel": "取消", "cancel": "取消",
"open": "開啟", "open": "開啟",
"export": "匯出", "export": "匯出",
"opening": "開啟...", "opening": "正在開啟...",
"exporting": "匯出..." "exporting": "正在匯出..."
}, },
"byok": { "byok": {
"description": "自帶 provider key。Nanobot 會從目前 config 讀取這些值,只有已設定的 provider 才能在一般設定中選擇。", "description": "自帶 provider key。Nanobot 會從目前 config 讀取這些值,只有已設定的 provider 才能在一般設定中選擇。",
@ -250,7 +250,7 @@
"tabs": { "tabs": {
"ariaLabel": "BYOK 憑證類型", "ariaLabel": "BYOK 憑證類型",
"llm": "LLM", "llm": "LLM",
"webSearch": "Web Search" "webSearch": "網頁搜尋"
}, },
"webSearch": { "webSearch": {
"provider": "搜尋 provider", "provider": "搜尋 provider",
@ -270,44 +270,44 @@
} }
}, },
"overview": { "overview": {
"model": "Current model", "model": "目前模型",
"providers": "Providers", "providers": "供應商",
"configuredCount": "{{count}} configured", "configuredCount": "已配置 {{count}} 個",
"totalProviders": "{{count}} available", "totalProviders": "共 {{count}} 個可用",
"webSearch": "Web search", "webSearch": "網頁搜尋",
"imageGeneration": "圖片生成", "imageGeneration": "圖片生成",
"workspace": "Workspace" "workspace": "工作區"
}, },
"providers": { "providers": {
"searchPlaceholder": "Search providers", "searchPlaceholder": "搜尋供應商",
"noMatches": "No providers match this search.", "noMatches": "沒有符合的供應商。",
"saveProvider": "儲存服務商" "saveProvider": "儲存供應商"
}, },
"image": { "image": {
"selectProvider": "選擇服務商", "selectProvider": "選擇供應商",
"selectAspect": "選擇比例", "selectAspect": "選擇比例",
"selectSize": "選擇尺寸", "selectSize": "選擇尺寸",
"configureProvider": "設定服務商", "configureProvider": "配置供應商",
"missingCredential": "啟用圖片生成前,請先設定此服務商。" "missingCredential": "啟用圖片生成前請先配置此供應商。"
}, },
"models": { "models": {
"selectModel": "選擇模型", "selectModel": "選擇模型",
"addConfiguration": "新增設定", "addConfiguration": "新增配置",
"newConfiguration": "新增模型設定", "newConfiguration": "新增模型配置",
"newConfigurationHelp": "把服務商和模型儲存為一個可直接切換的選項。", "newConfigurationHelp": "將供應商與模型儲存為一鍵選項。",
"configurationName": "設定名稱", "configurationName": "配置名稱",
"configurationNameHelp": "重新命名這個已儲存的模型配置。", "configurationNameHelp": "重新命名這個已儲存的模型配置。",
"configurationNamePlaceholder": "快速寫作", "configurationNamePlaceholder": "快速寫作",
"searchModels": "搜尋或輸入模型 ID", "searchModels": "搜尋或輸入模型 ID",
"useCustomModel": "使用", "useCustomModel": "使用",
"loadingModels": "正在載入模型...", "loadingModels": "正在載入模型...",
"searchCatalog": "搜尋服務商目錄來選擇模型。", "searchCatalog": "搜尋供應商目錄來選擇模型。",
"modelsAvailable": "可用", "modelsAvailable": "可用",
"noModelResults": "沒有符合的模型。", "noModelResults": "沒有符合的模型。",
"loadFailed": "模型列表不可用。", "loadFailed": "模型列表不可用。",
"unsupportedModelList": "手動輸入模型 ID。", "unsupportedModelList": "手動輸入模型 ID。",
"providerNotConfigured": "先設定這個服務商再載入模型。", "providerNotConfigured": "載入模型前請先配置此供應商。",
"autoProviderCustomOnly": "自動服務商模式使用自訂模型 ID。" "autoProviderCustomOnly": "自動供應商模式使用自訂模型 ID。"
}, },
"timezone": { "timezone": {
"select": "選擇時區", "select": "選擇時區",
@ -402,29 +402,29 @@
"thirdPartyBrands": "產品名稱、標誌與品牌均屬於其各自擁有者。使用僅為識別用途,並不代表背書。" "thirdPartyBrands": "產品名稱、標誌與品牌均屬於其各自擁有者。使用僅為識別用途,並不代表背書。"
}, },
"apps": { "apps": {
"description": "新增 nanobot 可在聊天中使用的 App CLI MCP 服務。", "description": "新增 nanobot 可在聊天中使用的 App CLI MCP 服務。",
"cliLabel": "CLI", "cliLabel": "CLI",
"mcpLabel": "MCP", "mcpLabel": "MCP",
"filterAll": "全部", "filterAll": "全部",
"filterCli": "CLI 應用", "filterCli": "CLI 應用",
"filterMcp": "MCP 服務", "filterMcp": "MCP 服務",
"enabledSummary": "已啟用 {{count}} 個", "enabledSummary": "已啟用 {{count}} 個",
"caption": "{{cli}} CLI · {{mcp}} MCP", "caption": "{{cli}} CLI · {{mcp}} MCP",
"searchPlaceholder": "搜尋應用", "searchPlaceholder": "搜尋應用",
"featured": "精選", "featured": "精選",
"loading": "正在載入應用...", "loading": "正在載入應用...",
"empty": "沒有符合篩選條件的應用。" "empty": "沒有符合的應用。"
}, },
"oauth": { "oauth": {
"authentication": "OAuth 證", "authentication": "OAuth 證",
"signIn": "登入", "signIn": "登入",
"signingIn": "正在登入…", "signingIn": "登入中...",
"signInAgain": "重新登入", "signInAgain": "重新登入",
"signOut": "登出", "signOut": "登出",
"signedInAs": "已登入為 {{account}}", "signedInAs": "已登入為 {{account}}",
"signInHelp": "在這台裝置上登入;不會把 API key 寫入設定。", "signInHelp": "從這台裝置登入;不會在配置中儲存 API key。",
"signInRequired": "需要登入", "signInRequired": "需要登入",
"signInBeforeSaving": "請先登入這個 OAuth 提供商,再儲存為目前模型提供商。", "signInBeforeSaving": "將此 OAuth 供應商設為目前模型供應商前,請先登入。",
"signedIn": "已登入", "signedIn": "已登入",
"notSignedIn": "未登入" "notSignedIn": "未登入"
} }

View File

@ -34,6 +34,60 @@ const SETTINGS_NAV_KEYS = [
"runtime", "runtime",
"advanced", "advanced",
]; ];
const LOCALIZED_SETTINGS_COPY_KEYS = [
"settings.backToChat",
"settings.sidebar.title",
"settings.sidebar.ariaLabel",
"settings.nav.overview",
"settings.nav.appearance",
"settings.nav.models",
"settings.nav.providers",
"settings.nav.apps",
"settings.nav.runtime",
"settings.nav.advanced",
"settings.sections.interface",
"settings.sections.localPreferences",
"settings.sections.webSearch",
"settings.sections.webBehavior",
"settings.sections.webuiSafety",
"settings.sections.capabilities",
"settings.sections.apps",
"settings.rows.theme",
"settings.rows.language",
"settings.rows.density",
"settings.rows.activityMode",
"settings.rows.codeWrap",
"settings.rows.brandLogos",
"settings.rows.currentModel",
"settings.rows.localServiceAccess",
"settings.rows.webuiDefaultAccess",
"settings.rows.contextWindow",
"settings.help.theme",
"settings.help.language",
"settings.help.density",
"settings.help.activityMode",
"settings.help.codeWrap",
"settings.help.brandLogos",
"settings.help.currentModel",
"settings.help.localServiceAccess",
"settings.help.webuiDefaultAccess",
"settings.values.light",
"settings.values.dark",
"settings.values.comfortable",
"settings.values.compact",
"settings.values.expanded",
"settings.values.enabled",
"settings.values.disabled",
"settings.values.defaultPermission",
"settings.values.fullAccess",
"settings.values.configured",
"settings.values.notConfigured",
"settings.status.loading",
"settings.status.unsaved",
"settings.status.upToDate",
"settings.actions.save",
"settings.actions.saving",
];
function isRecord(value: unknown): value is Record<string, unknown> { function isRecord(value: unknown): value is Record<string, unknown> {
return !!value && typeof value === "object" && !Array.isArray(value); return !!value && typeof value === "object" && !Array.isArray(value);
} }
@ -190,6 +244,20 @@ describe("webui i18n", () => {
} }
}); });
it("does not leak English settings chrome into localized locales", () => {
const english = flattenResource(resources.en.common);
for (const [locale, resource] of Object.entries(resources)) {
if (locale === "en") continue;
const current = flattenResource(resource.common);
const leaked = LOCALIZED_SETTINGS_COPY_KEYS.filter(
(key) => current.get(key) === english.get(key),
);
expect({ locale, leaked }).toEqual({ locale, leaked: [] });
}
});
it("keeps Simplified Chinese settings overview copy localized", () => { it("keeps Simplified Chinese settings overview copy localized", () => {
const settings = resources["zh-CN"].common.settings; const settings = resources["zh-CN"].common.settings;

View File

@ -194,7 +194,8 @@ describe("ThreadMessages", () => {
render(<ThreadMessages messages={messages} isStreaming />); render(<ThreadMessages messages={messages} isStreaming />);
expect(screen.getByLabelText(/editing foo\.txt/i)).toBeInTheDocument(); expect(screen.getByLabelText(/edited foo\.txt/i)).toBeInTheDocument();
expect(screen.queryByLabelText(/editing foo\.txt/i)).not.toBeInTheDocument();
}); });
it("folds final answer reasoning into the preceding activity timeline", () => { it("folds final answer reasoning into the preceding activity timeline", () => {

View File

@ -658,7 +658,7 @@ describe("useNanobotStream", () => {
}]); }]);
}); });
it("keeps interrupted pre-tool text inside activity before the final answer", async () => { it("keeps interrupted pre-tool text as assistant output before activity", async () => {
const fake = fakeClient(); const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-stream-segments", EMPTY_MESSAGES), { const { result } = renderHook(() => useNanobotStream("chat-stream-segments", EMPTY_MESSAGES), {
wrapper: wrap(fake.client), wrapper: wrap(fake.client),
@ -692,9 +692,7 @@ describe("useNanobotStream", () => {
expect(result.current.messages).toHaveLength(3); expect(result.current.messages).toHaveLength(3);
expect(result.current.messages[0]).toMatchObject({ expect(result.current.messages[0]).toMatchObject({
role: "assistant", role: "assistant",
content: "", content: "I created the files.",
reasoning: "I created the files.",
isStreaming: false,
}); });
expect(result.current.messages[1]).toMatchObject({ expect(result.current.messages[1]).toMatchObject({
role: "tool", role: "tool",
@ -739,9 +737,7 @@ describe("useNanobotStream", () => {
expect(result.current.messages).toHaveLength(3); expect(result.current.messages).toHaveLength(3);
expect(result.current.messages[0]).toMatchObject({ expect(result.current.messages[0]).toMatchObject({
role: "assistant", role: "assistant",
content: "", content: "I will inspect the project first.",
reasoning: "I will inspect the project first.",
isStreaming: false,
}); });
expect(result.current.messages[1]).toMatchObject({ expect(result.current.messages[1]).toMatchObject({
role: "tool", role: "tool",
@ -755,6 +751,51 @@ describe("useNanobotStream", () => {
}); });
}); });
it("splits live assistant output around tool hints without moving it into reasoning", async () => {
const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-live-segments", EMPTY_MESSAGES), {
wrapper: wrap(fake.client),
});
act(() => {
fake.emit("chat-live-segments", {
event: "delta",
chat_id: "chat-live-segments",
text: "Lint passed; now rendering the video.",
});
fake.emit("chat-live-segments", {
event: "message",
chat_id: "chat-live-segments",
text: 'exec({"cmd":"hyperframes render"})',
kind: "tool_hint",
});
fake.emit("chat-live-segments", {
event: "delta",
chat_id: "chat-live-segments",
text: "Rendered successfully.",
});
});
await flushStreamFrame();
expect(result.current.messages).toHaveLength(3);
expect(result.current.messages[0]).toMatchObject({
role: "assistant",
content: "Lint passed; now rendering the video.",
});
expect(result.current.messages[0].reasoning).toBeUndefined();
expect(result.current.messages[1]).toMatchObject({
role: "tool",
kind: "trace",
traces: ['exec({"cmd":"hyperframes render"})'],
});
expect(result.current.messages[2]).toMatchObject({
role: "assistant",
content: "Rendered successfully.",
});
expect(result.current.messages[2].reasoning).toBeUndefined();
});
it("opens a new activity segment for reasoning after file edit activity", async () => { it("opens a new activity segment for reasoning after file edit activity", async () => {
const fake = fakeClient(); const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-file-segments", EMPTY_MESSAGES), { const { result } = renderHook(() => useNanobotStream("chat-file-segments", EMPTY_MESSAGES), {
@ -967,7 +1008,7 @@ describe("useNanobotStream", () => {
expect(result.current.messages[0].reasoningStreaming).toBe(false); expect(result.current.messages[0].reasoningStreaming).toBe(false);
}); });
it("attaches post-hoc reasoning to the same assistant turn above the answer", () => { it("starts a new Thought block when reasoning arrives after visible output", () => {
const fake = fakeClient(); const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-r5", EMPTY_MESSAGES), { const { result } = renderHook(() => useNanobotStream("chat-r5", EMPTY_MESSAGES), {
wrapper: wrap(fake.client), wrapper: wrap(fake.client),
@ -988,12 +1029,61 @@ describe("useNanobotStream", () => {
fake.emit("chat-r5", { event: "reasoning_end", chat_id: "chat-r5" }); fake.emit("chat-r5", { event: "reasoning_end", chat_id: "chat-r5" });
}); });
expect(result.current.messages).toHaveLength(1); expect(result.current.messages).toHaveLength(2);
expect(result.current.messages[0].content).toBe("hi~"); expect(result.current.messages[0].content).toBe("hi~");
expect(result.current.messages[0].reasoning).toBe( expect(result.current.messages[0].reasoning).toBeUndefined();
expect(result.current.messages[1].content).toBe("");
expect(result.current.messages[1].reasoning).toBe(
"This reasoning arrived after the answer stream.", "This reasoning arrived after the answer stream.",
); );
expect(result.current.messages[0].reasoningStreaming).toBe(false); expect(result.current.messages[1].reasoningStreaming).toBe(false);
});
it("keeps alternating reasoning and answer deltas in separate ordered blocks", async () => {
const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-r5b", EMPTY_MESSAGES), {
wrapper: wrap(fake.client),
});
act(() => {
fake.emit("chat-r5b", {
event: "reasoning_delta",
chat_id: "chat-r5b",
text: "Plan first.",
});
fake.emit("chat-r5b", {
event: "delta",
chat_id: "chat-r5b",
text: "Visible progress.",
});
fake.emit("chat-r5b", {
event: "reasoning_delta",
chat_id: "chat-r5b",
text: "Think again.",
});
fake.emit("chat-r5b", {
event: "delta",
chat_id: "chat-r5b",
text: "Final visible text.",
});
});
await flushStreamFrame();
expect(result.current.messages).toHaveLength(2);
expect(result.current.messages[0]).toMatchObject({
role: "assistant",
reasoning: "Plan first.",
content: "Visible progress.",
});
expect(result.current.messages[1]).toMatchObject({
role: "assistant",
reasoning: "Think again.",
content: "Final visible text.",
});
expect(result.current.messages[1].activitySegmentId).not.toBe(
result.current.messages[0].activitySegmentId,
);
}); });
it("does not attach a new turn's reasoning across the latest user boundary", async () => { it("does not attach a new turn's reasoning across the latest user boundary", async () => {