diff --git a/ui/src/i18n/locales/en-US.ts b/ui/src/i18n/locales/en-US.ts index 60e268ec4..7ac1414a7 100644 --- a/ui/src/i18n/locales/en-US.ts +++ b/ui/src/i18n/locales/en-US.ts @@ -602,7 +602,57 @@ export const enUS = { tools: "Tools", gateway: "Gateway", wizard: "Setup Wizard", + meta: "Metadata", + logging: "Logging", + browser: "Browser", + ui: "UI", + models: "Models", + bindings: "Bindings", + broadcast: "Broadcast", + audio: "Audio", + session: "Session", + cron: "Cron", + web: "Web", + discovery: "Discovery", + canvasHost: "Canvas Host", + talk: "Talk", + plugins: "Plugins", }, + sectionDescriptions: { + env: "Environment variables passed to the gateway process", + update: "Auto-update settings and release channel", + agents: "Agent configurations, models, and identities", + auth: "API keys and authentication profiles", + channels: "Messaging channels (Telegram, Discord, Slack, etc.)", + messages: "Message handling and routing settings", + commands: "Custom slash commands", + hooks: "Webhooks and event hooks", + skills: "Skill packs and capabilities", + tools: "Tool configurations (browser, search, etc.)", + gateway: "Gateway server settings (port, auth, binding)", + wizard: "Setup wizard state and history", + meta: "Gateway metadata and version information", + logging: "Log levels and output configuration", + browser: "Browser automation settings", + ui: "User interface preferences", + models: "AI model configurations and providers", + bindings: "Key bindings and shortcuts", + broadcast: "Broadcast and notification settings", + audio: "Audio input/output settings", + session: "Session management and persistence", + cron: "Scheduled tasks and automation", + web: "Web server and API settings", + discovery: "Service discovery and networking", + canvasHost: "Canvas rendering and display", + talk: "Voice and speech settings", + plugins: "Plugin management and extensions", + }, + removeItem: "Remove item", + removeEntry: "Remove entry", + noSettingsMatch: "No settings match \"{{query}}\"", + noSettingsInSection: "No settings in this section", + schemaUnavailable: "Schema unavailable.", + unsupportedSchema: "Unsupported schema. Use Raw.", }, // Debug page @@ -663,22 +713,42 @@ export const enUS = { // Instances page instances: { title: "Instances", + cardTitle: "Connected Instances", desc: "Presence beacons from connected gateways and nodes.", + cardDesc: "Presence beacons from the gateway and clients.", noInstances: "No presence beacons found.", + noInstancesYet: "No instances reported yet.", id: "ID", type: "Type", version: "Version", lastSeen: "Last Seen", + lastInput: "Last input", + reason: "Reason", + unknownHost: "unknown host", + unknown: "unknown", + scopes: "scopes", + scopesCount: "{{count}} scopes", + secondsAgo: "{{count}}s ago", }, // Exec approval prompt execApproval: { title: "Execution Approval Required", + titleShort: "Exec approval needed", command: "Command", agent: "Agent", + session: "Session", + host: "Host", + cwd: "CWD", + resolved: "Resolved", + security: "Security", + ask: "Ask", allowOnce: "Allow Once", allowAlways: "Allow Always", deny: "Deny", + expiresIn: "expires in {{time}}", + expired: "expired", + pending: "{{count}} pending", }, // Theme @@ -704,6 +774,10 @@ export const enUS = { // Gateway connection gateway: { disconnected: "Disconnected from gateway.", + changeUrl: "Change Gateway URL", + changeUrlDesc: "This will reconnect to a different gateway server", + changeUrlWarning: "Only confirm if you trust this URL. Malicious URLs can compromise your system.", + confirm: "Confirm", }, // Nostr profile messages @@ -727,9 +801,13 @@ export const enUS = { // Markdown sidebar sidebar: { + title: "Tool Output", close: "Close", + closeSidebar: "Close sidebar", viewRaw: "View raw", + viewRawText: "View Raw Text", error: "Error loading content", + noContent: "No content available", }, // Errors diff --git a/ui/src/i18n/locales/zh-TW.ts b/ui/src/i18n/locales/zh-TW.ts index ba43dfeff..5967c3b7e 100644 --- a/ui/src/i18n/locales/zh-TW.ts +++ b/ui/src/i18n/locales/zh-TW.ts @@ -609,7 +609,57 @@ export const zhTW = { tools: "工具", gateway: "閘道器", wizard: "設定精靈", + meta: "中繼資料", + logging: "日誌", + browser: "瀏覽器", + ui: "使用者介面", + models: "模型", + bindings: "綁定", + broadcast: "廣播", + audio: "音訊", + session: "工作階段", + cron: "排程任務", + web: "網頁", + discovery: "服務探索", + canvasHost: "Canvas Host", + talk: "語音", + plugins: "外掛", }, + sectionDescriptions: { + env: "傳遞給閘道器程序的環境變數", + update: "自動更新設定與發行通道", + agents: "代理設定、模型與身分識別", + auth: "API 金鑰與認證設定檔", + channels: "訊息頻道(Telegram、Discord、Slack 等)", + messages: "訊息處理與路由設定", + commands: "自訂斜線指令", + hooks: "Webhooks 與事件鉤子", + skills: "Skills 套件與功能", + tools: "工具設定(瀏覽器、搜尋等)", + gateway: "閘道器伺服器設定(連接埠、認證、綁定)", + wizard: "設定精靈狀態與歷史記錄", + meta: "閘道器中繼資料與版本資訊", + logging: "日誌等級與輸出設定", + browser: "瀏覽器自動化設定", + ui: "使用者介面偏好設定", + models: "AI 模型設定與提供者", + bindings: "按鍵綁定與快捷鍵", + broadcast: "廣播與通知設定", + audio: "音訊輸入/輸出設定", + session: "工作階段管理與持久化", + cron: "排程任務與自動化", + web: "網頁伺服器與 API 設定", + discovery: "服務探索與網路設定", + canvasHost: "Canvas 渲染與顯示", + talk: "語音與語音設定", + plugins: "外掛管理與擴充功能", + }, + removeItem: "移除項目", + removeEntry: "移除項目", + noSettingsMatch: "找不到符合「{{query}}」的設定", + noSettingsInSection: "此區塊沒有設定", + schemaUnavailable: "結構定義不可用。", + unsupportedSchema: "不支援的結構定義。請使用原始模式。", }, // 除錯頁面 @@ -670,22 +720,42 @@ export const zhTW = { // 實例頁面 instances: { title: "實例", + cardTitle: "已連線的實例", desc: "來自已連線閘道器與節點的存在訊號。", + cardDesc: "來自閘道器與用戶端的存在訊號。", noInstances: "找不到存在訊號。", + noInstancesYet: "尚無實例回報。", id: "識別碼", type: "類型", version: "版本", lastSeen: "上次出現", + lastInput: "上次輸入", + reason: "原因", + unknownHost: "未知主機", + unknown: "未知", + scopes: "範圍", + scopesCount: "{{count}} 個範圍", + secondsAgo: "{{count}} 秒前", }, // 執行核准提示 execApproval: { title: "需要執行核准", + titleShort: "需要執行核准", command: "指令", agent: "代理", + session: "工作階段", + host: "主機", + cwd: "工作目錄", + resolved: "解析路徑", + security: "安全性", + ask: "詢問", allowOnce: "允許一次", allowAlways: "永久允許", deny: "拒絕", + expiresIn: "{{time}} 後過期", + expired: "已過期", + pending: "{{count}} 個待處理", }, // 主題 @@ -711,6 +781,10 @@ export const zhTW = { // 閘道器連線 gateway: { disconnected: "已與閘道器斷線。", + changeUrl: "變更閘道器網址", + changeUrlDesc: "這將重新連線到不同的閘道器伺服器", + changeUrlWarning: "僅在您信任此網址時才確認。惡意網址可能會危害您的系統。", + confirm: "確認", }, // Nostr 個人檔案訊息 @@ -734,9 +808,13 @@ export const zhTW = { // Markdown 側邊欄 sidebar: { + title: "工具輸出", close: "關閉", + closeSidebar: "關閉側邊欄", viewRaw: "檢視原始內容", + viewRawText: "檢視原始文字", error: "載入內容時發生錯誤", + noContent: "沒有可用的內容", }, // 錯誤訊息 diff --git a/ui/src/ui/views/config-form.node.ts b/ui/src/ui/views/config-form.node.ts index 17a182281..14b7cb6f2 100644 --- a/ui/src/ui/views/config-form.node.ts +++ b/ui/src/ui/views/config-form.node.ts @@ -1,4 +1,6 @@ import { html, nothing, type TemplateResult } from "lit"; + +import { t } from "../../i18n"; import type { ConfigUiHints } from "../types"; import { defaultValue, @@ -533,7 +535,7 @@ function renderArray(params: { diff --git a/ui/src/ui/views/gateway-url-confirmation.ts b/ui/src/ui/views/gateway-url-confirmation.ts index 7d48c4367..97038efe1 100644 --- a/ui/src/ui/views/gateway-url-confirmation.ts +++ b/ui/src/ui/views/gateway-url-confirmation.ts @@ -1,5 +1,6 @@ import { html, nothing } from "lit"; +import { t } from "../../i18n"; import type { AppViewState } from "../app-view-state"; export function renderGatewayUrlConfirmation(state: AppViewState) { @@ -11,26 +12,26 @@ export function renderGatewayUrlConfirmation(state: AppViewState) {
-
Change Gateway URL
-
This will reconnect to a different gateway server
+
${t("gateway.changeUrl")}
+
${t("gateway.changeUrlDesc")}
${pendingGatewayUrl}
- Only confirm if you trust this URL. Malicious URLs can compromise your system. + ${t("gateway.changeUrlWarning")}
diff --git a/ui/src/ui/views/instances.ts b/ui/src/ui/views/instances.ts index 43a4f4191..32640df5e 100644 --- a/ui/src/ui/views/instances.ts +++ b/ui/src/ui/views/instances.ts @@ -1,5 +1,6 @@ import { html, nothing } from "lit"; +import { t } from "../../i18n"; import { formatPresenceAge, formatPresenceSummary } from "../presenter"; import type { PresenceEntry } from "../types"; @@ -16,11 +17,11 @@ export function renderInstances(props: InstancesProps) {
-
Connected Instances
-
Presence beacons from the gateway and clients.
+
${t("instances.cardTitle")}
+
${t("instances.cardDesc")}
${props.lastError @@ -35,7 +36,7 @@ export function renderInstances(props: InstancesProps) { : nothing}
${props.entries.length === 0 - ? html`
No instances reported yet.
` + ? html`
${t("instances.noInstancesYet")}
` : props.entries.map((entry) => renderEntry(entry))}
@@ -45,21 +46,21 @@ export function renderInstances(props: InstancesProps) { function renderEntry(entry: PresenceEntry) { const lastInput = entry.lastInputSeconds != null - ? `${entry.lastInputSeconds}s ago` - : "n/a"; - const mode = entry.mode ?? "unknown"; + ? t("instances.secondsAgo", { count: entry.lastInputSeconds }) + : t("common.na"); + const mode = entry.mode ?? t("instances.unknown"); const roles = Array.isArray(entry.roles) ? entry.roles.filter(Boolean) : []; const scopes = Array.isArray(entry.scopes) ? entry.scopes.filter(Boolean) : []; const scopesLabel = scopes.length > 0 ? scopes.length > 3 - ? `${scopes.length} scopes` - : `scopes: ${scopes.join(", ")}` + ? t("instances.scopesCount", { count: scopes.length }) + : `${t("instances.scopes")}: ${scopes.join(", ")}` : null; return html`
-
${entry.host ?? "unknown host"}
+
${entry.host ?? t("instances.unknownHost")}
${formatPresenceSummary(entry)}
${mode} @@ -77,8 +78,8 @@ function renderEntry(entry: PresenceEntry) {
${formatPresenceAge(entry)}
-
Last input ${lastInput}
-
Reason ${entry.reason ?? ""}
+
${t("instances.lastInput")} ${lastInput}
+
${t("instances.reason")} ${entry.reason ?? ""}
`; diff --git a/ui/src/ui/views/markdown-sidebar.ts b/ui/src/ui/views/markdown-sidebar.ts index 828c524a3..718691984 100644 --- a/ui/src/ui/views/markdown-sidebar.ts +++ b/ui/src/ui/views/markdown-sidebar.ts @@ -1,6 +1,7 @@ import { html, nothing } from "lit"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { t } from "../../i18n"; import { icons } from "../icons"; import { toSanitizedMarkdownHtml } from "../markdown"; @@ -15,8 +16,8 @@ export function renderMarkdownSidebar(props: MarkdownSidebarProps) { return html`
`; diff --git a/ui/src/ui/views/nodes.ts b/ui/src/ui/views/nodes.ts index 947bc543e..215c2115c 100644 --- a/ui/src/ui/views/nodes.ts +++ b/ui/src/ui/views/nodes.ts @@ -274,17 +274,21 @@ type ExecApprovalsState = { const EXEC_APPROVALS_DEFAULT_SCOPE = "__defaults__"; -const SECURITY_OPTIONS: Array<{ value: ExecSecurity; label: string }> = [ - { value: "deny", label: "Deny" }, - { value: "allowlist", label: "Allowlist" }, - { value: "full", label: "Full" }, -]; +function getSecurityOptions(): Array<{ value: ExecSecurity; label: string }> { + return [ + { value: "deny", label: t("nodes.approvals.deny") }, + { value: "allowlist", label: t("nodes.approvals.allowlist") }, + { value: "full", label: t("nodes.approvals.full") }, + ]; +} -const ASK_OPTIONS: Array<{ value: ExecAsk; label: string }> = [ - { value: "off", label: "Off" }, - { value: "on-miss", label: "On miss" }, - { value: "always", label: "Always" }, -]; +function getAskOptions(): Array<{ value: ExecAsk; label: string }> { + return [ + { value: "off", label: t("nodes.approvals.off") }, + { value: "on-miss", label: t("nodes.approvals.onMiss") }, + { value: "always", label: t("nodes.approvals.always") }, + ]; +} function resolveBindingsState(props: NodesProps): BindingState { const config = props.configForm; @@ -696,7 +700,7 @@ function renderExecApprovalsPolicy(state: ExecApprovalsState) { Use default (${defaults.security}) ` : nothing} - ${SECURITY_OPTIONS.map( + ${getSecurityOptions().map( (option) => html`