diff --git a/packages/app/src/app/components/session/artifact-markdown-editor.tsx b/packages/app/src/app/components/session/artifact-markdown-editor.tsx index 3f26426f..cfd80805 100644 --- a/packages/app/src/app/components/session/artifact-markdown-editor.tsx +++ b/packages/app/src/app/components/session/artifact-markdown-editor.tsx @@ -1,4 +1,5 @@ import { Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js"; +import { t } from "../../../i18n"; import { FileText, RefreshCcw, Save, X } from "lucide-solid"; import Button from "../button"; @@ -35,13 +36,13 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp const [pendingReason, setPendingReason] = createSignal<"switch" | null>(null); const path = createMemo(() => props.path?.trim() ?? ""); - const title = createMemo(() => (path() ? basename(path()) : "Artifact")); + const title = createMemo(() => (path() ? basename(path()) : t("session.editor_default_title"))); const dirty = createMemo(() => draft() !== original()); const canWrite = createMemo(() => Boolean(props.client && props.workspaceId)); const canSave = createMemo(() => dirty() && !saving() && canWrite()); const writeDisabledReason = createMemo(() => { if (canWrite()) return null; - return "Connect to an OpenWork server worker to edit files."; + return t("session.editor_connect_hint"); }); const resetState = () => { @@ -71,7 +72,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp return; } if (!isMarkdown(target)) { - setError("Only markdown files are supported."); + setError(t("session.editor_toast_markdown_only")); return; } @@ -102,7 +103,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp result = (await client.readWorkspaceFile(workspaceId, actualPath)) as OpenworkWorkspaceFileContent; } catch (second) { if (second instanceof OpenworkServerError && second.status === 404) { - throw new OpenworkServerError(404, "file_not_found", "File not found (workspace root or outbox)."); + throw new OpenworkServerError(404, "file_not_found", t("session.editor_toast_not_found")); } throw second; } @@ -114,7 +115,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp setResolvedPath(actualPath); setBaseUpdatedAt(typeof result.updatedAt === "number" ? result.updatedAt : null); } catch (err) { - const message = err instanceof Error ? err.message : "Failed to load file"; + const message = err instanceof Error ? err.message : t("session.editor_toast_load_failed"); setError(message); setLoadedPath(target); } finally { @@ -127,11 +128,11 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp const workspaceId = props.workspaceId; const target = resolvedPath() ?? path(); if (!client || !workspaceId || !target) { - props.onToast?.("Cannot save: OpenWork server not connected"); + props.onToast?.(t("session.editor_toast_save_connect")); return; } if (!isMarkdown(target)) { - props.onToast?.("Only markdown files are supported"); + props.onToast?.(t("session.editor_toast_markdown_only")); return; } if (!dirty()) return; @@ -160,7 +161,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp setConfirmOverwrite(true); return; } - const message = err instanceof Error ? err.message : "Failed to save"; + const message = err instanceof Error ? err.message : t("session.editor_toast_save_failed"); setError(message); props.onToast?.(message); } finally { @@ -185,7 +186,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp return; } // Reload is destructive; reuse the close-discard banner semantics. - setError("Discard changes to reload from disk (close and reopen), or save first."); + setError(t("session.editor_toast_reload_discard")); }; createEffect(() => { @@ -241,7 +242,7 @@ export default function ArtifactMarkdownEditor(props: ArtifactMarkdownEditorProp
@@ -324,9 +326,9 @@ export default function ConfigView(props: ConfigViewProps) {
- OpenWork server sharing
+ {t("config.sharing_title")}
- Share these details with a trusted device. Keep the server on the same network for the fastest setup.
+ {t("config.sharing_subtitle")}
@@ -337,13 +339,13 @@ export default function ConfigView(props: ConfigViewProps) {
- OpenWork Server URL
- {hostConnectUrl() || "Starting server…"}
+ {t("config.server_url_label")}
+ {hostConnectUrl() || t("config.starting_server")}
{hostConnectUrlUsesMdns()
- ? ".local names are easier to remember but may not resolve on all networks."
- : "Use your local IP on the same Wi-Fi for the fastest connection."}
+ ? t("config.mdns_hint")
+ : t("config.ip_hint")}
@@ -353,13 +355,13 @@ export default function ConfigView(props: ConfigViewProps) {
onClick={() => handleCopy(hostConnectUrl(), "host-url")}
disabled={!hostConnectUrl()}
>
- {copyingField() === "host-url" ? "Copied" : "Copy"}
+ {copyingField() === "host-url" ? t("config.copied") : t("config.copy")}
- Access token
+ {t("config.access_token_label")}
{clientTokenVisible()
? hostInfo()?.clientToken || "—"
@@ -367,7 +369,7 @@ export default function ConfigView(props: ConfigViewProps) {
? "••••••••••••"
: "—"}
- Use on phones or laptops connecting to this server.
+ {t("config.access_token_hint")}
setClientTokenVisible((prev) => !prev)}
disabled={!hostInfo()?.clientToken}
>
- {clientTokenVisible() ? "Hide" : "Show"}
+ {clientTokenVisible() ? t("config.hide") : t("config.show")}
handleCopy(hostInfo()?.clientToken ?? "", "client-token")}
disabled={!hostInfo()?.clientToken}
>
- {copyingField() === "client-token" ? "Copied" : "Copy"}
+ {copyingField() === "client-token" ? t("config.copied") : t("config.copy")}
- Server token
+ {t("config.server_token_label")}
{hostTokenVisible()
? hostInfo()?.hostToken || "—"
@@ -399,7 +401,7 @@ export default function ConfigView(props: ConfigViewProps) {
? "••••••••••••"
: "—"}
- Keep private. Required for approval actions.
+ {t("config.server_token_hint")}
setHostTokenVisible((prev) => !prev)}
disabled={!hostInfo()?.hostToken}
>
- {hostTokenVisible() ? "Hide" : "Show"}
+ {hostTokenVisible() ? t("config.hide") : t("config.show")}
handleCopy(hostInfo()?.hostToken ?? "", "host-token")}
disabled={!hostInfo()?.hostToken}
>
- {copyingField() === "host-token" ? "Copied" : "Copy"}
+ {copyingField() === "host-token" ? t("config.copied") : t("config.copy")}
-
- For per-workspace sharing links, use Share... in the workspace menu.
-
+
- OpenWork server
+ {t("config.openwork_server_title")}
- Connect to an OpenWork server. Use the URL and access token from your server admin.
+ {t("config.openwork_server_subtitle")}
{openworkStatusLabel()}
@@ -441,22 +441,22 @@ export default function ConfigView(props: ConfigViewProps) {
setOpenworkUrl(event.currentTarget.value)}
- placeholder="http://127.0.0.1:8787"
- hint="Use the URL shared by your OpenWork server."
+ placeholder={t("dashboard.remote_base_url_placeholder")}
+ hint={t("dashboard.openwork_host_hint")}
disabled={props.busy}
/>
- Resolved worker URL: {resolvedWorkspaceUrl() || "Not set"}
- Worker ID: {resolvedWorkspaceId() || "Unavailable"}
+ {t("config.resolved_worker_url")}{resolvedWorkspaceUrl() || t("config.not_set")}
+ {t("config.worker_id")}{resolvedWorkspaceId() || t("config.unavailable")}
@@ -491,27 +491,27 @@ export default function ConfigView(props: ConfigViewProps) {
const ok = await props.testOpenworkServerConnection(next);
setOpenworkTestState(ok ? "success" : "error");
setOpenworkTestMessage(
- ok ? "Connection successful." : "Connection failed. Check the host URL and token.",
+ ok ? t("config.connection_success") : t("config.connection_failed")
);
} catch (error) {
- const message = error instanceof Error ? error.message : "Connection failed.";
+ const message = error instanceof Error ? error.message : t("config.connection_failed_generic");
setOpenworkTestState("error");
setOpenworkTestMessage(message);
}
}}
disabled={props.busy || openworkTestState() === "testing"}
>
- {openworkTestState() === "testing" ? "Testing..." : "Test connection"}
+ {openworkTestState() === "testing" ? t("config.testing") : t("config.test_connection")}
props.updateOpenworkServerSettings(buildOpenworkSettings())}
disabled={props.busy || !hasOpenworkChanges()}
>
- Save
+ {t("config.save")}
- Reset
+ {t("config.reset")}
@@ -527,25 +527,23 @@ export default function ConfigView(props: ConfigViewProps) {
role="status"
aria-live="polite"
>
- {openworkTestState() === "testing" ? "Testing connection..." : openworkTestMessage() ?? "Connection status updated."}
+ {openworkTestState() === "testing" ? t("config.testing_connection") : openworkTestMessage() ?? t("config.connection_status_updated")}
-
- OpenWork server connection needed to sync skills, plugins, and commands.
+
+ {t("config.sync_hint")}
- Messaging identities
-
- Manage Telegram/Slack identities and routing in the Identities tab.
-
+ {t("config.identities_title")}
+
- Some config features (local server sharing + messaging bridge) require the desktop app.
+ {t("config.desktop_only_hint")}
diff --git a/packages/app/src/app/pages/dashboard.tsx b/packages/app/src/app/pages/dashboard.tsx
index c8823df0..dd7d5908 100644
--- a/packages/app/src/app/pages/dashboard.tsx
+++ b/packages/app/src/app/pages/dashboard.tsx
@@ -14,6 +14,7 @@ import type {
WorkspaceSessionGroup,
View,
} from "../types";
+import { t } from "../../i18n";
import type { McpDirectoryInfo } from "../constants";
import {
formatRelativeTime,
@@ -289,23 +290,23 @@ export default function DashboardView(props: DashboardViewProps) {
const title = createMemo(() => {
switch (props.tab) {
case "scheduled":
- return "Automations";
+ return t("dashboard.tab_automations");
case "soul":
return "Soul";
case "skills":
- return "Skills";
+ return t("dashboard.tab_skills");
case "plugins":
- return "Extensions";
+ return t("dashboard.tab_extensions");
case "mcp":
- return "Extensions";
+ return t("dashboard.tab_extensions");
case "identities":
return "Messaging";
case "config":
- return "Advanced";
+ return t("dashboard.tab_advanced");
case "settings":
- return "Settings";
+ return t("dashboard.tab_settings");
default:
- return "Automations";
+ return t("dashboard.tab_automations");
}
});
@@ -314,15 +315,15 @@ export default function DashboardView(props: DashboardViewProps) {
workspace.openworkWorkspaceName?.trim() ||
workspace.name?.trim() ||
workspace.path?.trim() ||
- "Worker";
+ t("dashboard.workspace_worker");
const workspaceKindLabel = (workspace: WorkspaceInfo) =>
workspace.workspaceType === "remote"
? workspace.sandboxBackend === "docker" ||
Boolean(workspace.sandboxRunId?.trim()) ||
Boolean(workspace.sandboxContainerName?.trim())
- ? "Sandbox"
- : "Remote"
- : "Local";
+ ? t("dashboard.workspace_sandbox")
+ : t("dashboard.workspace_remote")
+ : t("dashboard.workspace_local");
const openSessionFromList = (workspaceId: string, sessionId: string) => {
// Route-driven selection: navigate first and let the route effect own selectSession.
@@ -412,7 +413,7 @@ export default function DashboardView(props: DashboardViewProps) {
const showMoreLabel = (workspaceId: string, total: number) => {
const remaining = Math.max(0, total - previewCount(workspaceId));
const nextCount = Math.min(MAX_SESSIONS_PREVIEW, remaining);
- return nextCount > 0 ? `Show ${nextCount} more` : "Show more";
+ return nextCount > 0 ? t("dashboard.show_more_count").replace("{count}", nextCount.toString()) : t("dashboard.show_more");
};
const [workspaceMenuId, setWorkspaceMenuId] = createSignal(null);
let workspaceMenuRef: HTMLDivElement | undefined;
@@ -654,23 +655,23 @@ export default function DashboardView(props: DashboardViewProps) {
const token = props.openworkServerHostInfo?.clientToken?.trim() || "";
return [
{
- label: "OpenWork worker URL",
+ label: t("dashboard.share_worker_url"),
value: url,
- placeholder: !isTauriRuntime() ? "Desktop app required" : "Starting server...",
+ placeholder: !isTauriRuntime() ? t("dashboard.share_desktop_required") : t("dashboard.share_starting_server"),
hint: mountedUrl
- ? "Use on phones or laptops connecting to this worker."
+ ? t("dashboard.share_worker_hint")
: hostUrl
- ? "Worker URL is resolving; host URL shown as fallback."
+ ? t("dashboard.share_resolving_hint")
: undefined,
},
{
- label: "Access token",
+ label: t("config.access_token_label"),
value: token,
secret: true,
- placeholder: isTauriRuntime() ? "-" : "Desktop app required",
+ placeholder: isTauriRuntime() ? "-" : t("dashboard.share_desktop_required"),
hint: mountedUrl
- ? "Use on phones or laptops connecting to this worker."
- : "Use on phones or laptops connecting to this host.",
+ ? t("dashboard.share_worker_hint")
+ : t("dashboard.share_host_hint"),
},
];
}
@@ -684,15 +685,15 @@ export default function DashboardView(props: DashboardViewProps) {
"";
return [
{
- label: "OpenWork worker URL",
+ label: t("dashboard.share_worker_url"),
value: url,
},
{
- label: "Access token",
+ label: t("config.access_token_label"),
value: token,
secret: true,
- placeholder: token ? undefined : "Set token in Advanced",
- hint: "This token grants access to the worker on that host.",
+ placeholder: token ? undefined : t("dashboard.share_token_advanced_hint"),
+ hint: t("dashboard.share_token_grant_hint"),
},
];
}
@@ -701,13 +702,13 @@ export default function DashboardView(props: DashboardViewProps) {
const directory = ws.directory?.trim() || "";
return [
{
- label: "OpenCode base URL",
+ label: t("dashboard.share_opencode_url"),
value: baseUrl,
},
{
- label: "Directory",
+ label: t("dashboard.share_directory"),
value: directory,
- placeholder: "(auto)",
+ placeholder: t("dashboard.share_auto"),
},
];
});
@@ -716,17 +717,17 @@ export default function DashboardView(props: DashboardViewProps) {
const ws = shareWorkspace();
if (!ws) return null;
if (ws.workspaceType === "local" && props.engineInfo?.runtime === "direct") {
- return "Engine runtime is set to Direct. Switching local workers can restart the host and disconnect clients. The token may change after a restart.";
+ return t("dashboard.share_direct_warning");
}
return null;
});
const exportDisabledReason = createMemo(() => {
const ws = shareWorkspace();
- if (!ws) return "Export is available for local workers in the desktop app.";
- if (ws.workspaceType === "remote") return "Export is only supported for local workers.";
- if (!isTauriRuntime()) return "Export is available in the desktop app.";
- if (props.exportWorkspaceBusy) return "Export is already running.";
+ if (!ws) return t("dashboard.export_local_desktop");
+ if (ws.workspaceType === "remote") return t("dashboard.export_local_only");
+ if (!isTauriRuntime()) return t("dashboard.export_desktop_only");
+ if (props.exportWorkspaceBusy) return t("dashboard.export_running");
return null;
});
@@ -747,13 +748,13 @@ export default function DashboardView(props: DashboardViewProps) {
const updatePillLabel = createMemo(() => {
const state = props.updateStatus?.state;
if (state === "ready") {
- return props.anyActiveRuns ? "Update ready" : "Install update";
+ return props.anyActiveRuns ? t("dashboard.update_ready_btn") : t("dashboard.install_update_btn");
}
if (state === "downloading") {
const percent = updateDownloadPercent();
- return percent == null ? "Downloading" : `Downloading ${percent}%`;
+ return percent == null ? t("dashboard.downloading_btn") : t("dashboard.downloading_percent_btn").replace("{percent}", percent.toString());
}
- return "Update available";
+ return t("dashboard.update_available_btn");
});
const updatePillButtonTone = createMemo(() => {
@@ -807,11 +808,11 @@ export default function DashboardView(props: DashboardViewProps) {
const state = props.updateStatus?.state;
if (state === "ready") {
return props.anyActiveRuns
- ? `Update ready ${version}. Stop active runs to restart.`
- : `Restart to apply update ${version}`;
+ ? t("dashboard.update_ready_tooltip").replace("{version}", version)
+ : t("dashboard.update_restart_tooltip").replace("{version}", version);
}
- if (state === "downloading") return `Downloading update ${version}`;
- return `Update available ${version}`;
+ if (state === "downloading") return t("dashboard.update_downloading_tooltip").replace("{version}", version);
+ return t("dashboard.update_available_tooltip").replace("{version}", version);
});
const handleUpdatePillClick = () => {
@@ -973,7 +974,7 @@ export default function DashboardView(props: DashboardViewProps) {
setWorkspaceMenuId(null);
}}
>
- Edit name
+ {t("dashboard.menu_edit_name")}
- Share...
+ {t("dashboard.menu_share")}
- Test connection
+ {t("dashboard.menu_test_connection")}
- Edit connection
+ {t("dashboard.menu_edit_connection")}
@@ -1028,7 +1029,7 @@ export default function DashboardView(props: DashboardViewProps) {
setWorkspaceMenuId(null);
}}
>
- Stop sandbox
+ {t("dashboard.menu_stop_sandbox")}
- Remove worker
+ {t("dashboard.menu_remove_worker")}
@@ -1141,8 +1142,8 @@ export default function DashboardView(props: DashboardViewProps) {
onClick={() => createTaskInWorkspace(workspace().id)}
disabled={props.newTaskDisabled}
>
- No tasks yet.
- + New task
+ {t("dashboard.tasks_empty")}
+ {t("dashboard.tasks_new")}
@@ -1159,7 +1160,7 @@ export default function DashboardView(props: DashboardViewProps) {
}
>
- Loading tasks...
+ {t("dashboard.loading_tasks")}
@@ -1177,7 +1178,7 @@ export default function DashboardView(props: DashboardViewProps) {
onClick={() => setAddWorkspaceMenuOpen((prev) => !prev)}
>
- Add a worker
+ {t("dashboard.add_worker")}
@@ -1190,7 +1191,7 @@ export default function DashboardView(props: DashboardViewProps) {
}}
>
- New worker
+ {t("dashboard.new_worker")}
- Connect remote
+ {t("dashboard.connect_remote")}
- Import config
+ {t("dashboard.import_config")}
@@ -1519,7 +1520,7 @@ export default function DashboardView(props: DashboardViewProps) {
onClick={props.repairOpencodeCache}
disabled={props.cacheRepairBusy || !props.developerMode}
>
- {props.cacheRepairBusy ? "Repairing cache" : "Repair cache"}
+ {props.cacheRepairBusy ? t("dashboard.repairing_cache_btn") : t("dashboard.repair_cache_btn")}
- Retry
+ {t("dashboard.retry")}
@@ -1594,7 +1595,7 @@ export default function DashboardView(props: DashboardViewProps) {
onClick={() => props.setTab("scheduled")}
>
- Automations
+ {t("dashboard.tab_automations")}
props.setTab("skills")}
>
- Skills
+ {t("dashboard.tab_skills")}
props.setTab("mcp")}
>
- Extensions
+ {t("dashboard.tab_extensions")}
props.setTab("identities")}
>
- IDs
+ {t("dashboard.nav_ids")}
props.setTab("config")}
>
- Advanced
+ {t("dashboard.tab_advanced")}
@@ -1649,12 +1650,12 @@ export default function DashboardView(props: DashboardViewProps) {
- Apps (MCP) and OpenCode plugins live in one place. + {t("extensions.description")}
- Let people reach your worker through messaging apps. Connect a channel and - your worker will automatically read and respond to messages. + {t("identities.description")}
openwork).
- /w/<workspace-id>) or select a workspace mapped on this host.
- /newbot.
-
+
/start to your bot to activate the chat.
+
- Connect your Slack workspace to let team members interact with this worker in channels and DMs. + {t("identities.slack_hint")}
- Control which conversations go to which workspace folder. Messages are - routed to the worker's default folder unless you set up rules here. + {t("identities.message_routing_description")}
/dir <path> in Slack/Telegram to override the directory for a specific chat (limited to this workspace root).
- @agent <id> to route via a specific OpenCode agent.
- {sourceDescription()}
@@ -756,14 +761,14 @@ export default function ScheduledTasksView(props: ScheduledTasksViewProps) { fallback={{deleteDescription()}
- Automations are scheduled by running a prompt in a new thread. We’ll prefill - a prompt for you to send. + {t("scheduled.create_modal_desc")}
- Pick a starting point or just type below. + {t("session.hero_description")}
OpenCode is requesting permission to continue.
+{t("session.permission_description")}
{props.safeStringify(props.activePermission?.metadata)}
@@ -3677,7 +3682,7 @@ export default function SessionView(props: SessionViewProps) {
disabled={props.permissionReplyBusy}
>
- Deny
+ {t("session.deny")}
- This clears your saved preference and shows the connection choice on next launch. + {translate("settings.reset_startup_hint")}
{engineStdout()}
{engineStderr()}
@@ -1426,8 +1430,8 @@ export default function SettingsView(props: SettingsViewProps) {
{props.orchestratorStatus?.lastError}
@@ -1469,8 +1473,8 @@ export default function SettingsView(props: SettingsViewProps) {
{props.opencodeConnectStatus?.error}
@@ -1526,8 +1530,8 @@ export default function SettingsView(props: SettingsViewProps) {
{openworkStdout()}
{openworkStderr()}
@@ -1558,8 +1562,8 @@ export default function SettingsView(props: SettingsViewProps) {
{opencodeRouterStdout()}
{opencodeRouterStderr()}
@@ -1619,27 +1623,27 @@ export default function SettingsView(props: SettingsViewProps) {
{props.safeStringify(props.pendingPermissions)}
{props.safeStringify(props.events)}
@@ -1709,14 +1713,14 @@ export default function SettingsView(props: SettingsViewProps) {
@@ -1726,7 +1730,7 @@ export default function SettingsView(props: SettingsViewProps) {
- Audit log
+ {translate("settings.devtools.audit_log")}
{openworkAuditStatusLabel()}
@@ -1736,7 +1740,7 @@ export default function SettingsView(props: SettingsViewProps) {
0}
- fallback={No audit entries yet.}
+ fallback={{translate("settings.devtools.no_audit_entries")}}
>
@@ -1765,4 +1769,4 @@ export default function SettingsView(props: SettingsViewProps) {
);
-}
+}
\ No newline at end of file
diff --git a/packages/app/src/app/pages/skills.tsx b/packages/app/src/app/pages/skills.tsx
index b16e51f0..aae69cfa 100644
--- a/packages/app/src/app/pages/skills.tsx
+++ b/packages/app/src/app/pages/skills.tsx
@@ -491,10 +491,10 @@ export default function SkillsView(props: SkillsViewProps) {
- Worker profile
+ {translate("skills.worker_profile")}
{workspaceLabel()}
- Skills are the core abilities of this worker. Add from Hub or create new ones directly in chat.
+ {translate("skills.worker_profile_desc")}
- Create skill in chat
+ {translate("skills.create_in_chat")}
- Installed
+ {translate("skills.stat_installed")}
{props.skills.length}
- Hub available
+ {translate("skills.stat_hub_available")}
{availableHubSkills().length}
- Skill creator
+ {translate("skills.stat_skill_creator")}
- {skillCreatorInstalled() ? "Installed" : "Not installed"}
+ {skillCreatorInstalled() ? translate("skills.stat_installed") : translate("skills.stat_not_installed")}
- Mode
+ {translate("skills.stat_mode")}
- {props.canUseDesktopTools ? "Local" : "Server"}
+ {props.canUseDesktopTools ? translate("skills.mode_local") : translate("skills.mode_server")}
@@ -556,7 +556,7 @@ export default function SkillsView(props: SkillsViewProps) {
type="text"
value={searchQuery()}
onInput={(event) => setSearchQuery(event.currentTarget.value)}
- placeholder="Search installed or hub skills"
+ placeholder={translate("skills.search_placeholder")}
class="bg-dls-hover border border-dls-border rounded-lg py-1.5 pl-9 pr-4 text-xs w-56 focus:w-72 focus:outline-none transition-all"
/>
@@ -571,7 +571,7 @@ export default function SkillsView(props: SkillsViewProps) {
}`}
>
- New skill
+ {translate("skills.new_skill")}
- Install from link
+ {translate("skills.install_link")}
@@ -663,7 +663,7 @@ export default function SkillsView(props: SkillsViewProps) {
openShareLink(skill);
}}
disabled={props.busy}
- title="Share link"
+ title={translate("skills.share_link_title")}
>
@@ -676,7 +676,7 @@ export default function SkillsView(props: SkillsViewProps) {
void openSkill(skill);
}}
disabled={props.busy}
- title="Edit"
+ title={translate("skills.edit")}
>
@@ -708,7 +708,7 @@ export default function SkillsView(props: SkillsViewProps) {
- Install skills
+ {translate("skills.install_title")}
props.refreshHubSkills({ force: true })}
@@ -718,10 +718,10 @@ export default function SkillsView(props: SkillsViewProps) {
? "text-dls-secondary"
: "text-dls-secondary hover:text-dls-text"
}`}
- title="Refresh hub catalog"
+ title={translate("skills.refresh_hub_hint")}
>
- Refresh hub
+ {translate("skills.refresh_hub")}
@@ -735,7 +735,7 @@ export default function SkillsView(props: SkillsViewProps) {
when={filteredHubSkills().length}
fallback={
- No hub skills available.
+ {translate("skills.no_hub_skills")}
}
>
@@ -751,7 +751,7 @@ export default function SkillsView(props: SkillsViewProps) {
{skill.name}
- From openwork-hub}>
+ {translate("skills.from_hub")}}>
{skill.description}
@@ -760,7 +760,7 @@ export default function SkillsView(props: SkillsViewProps) {
- Trigger: {skill.trigger}
+ {translate("skills.trigger_label").replace("{trigger}", skill.trigger ?? "")}
@@ -779,7 +779,7 @@ export default function SkillsView(props: SkillsViewProps) {
void installFromHub(skill);
}}
disabled={props.busy || installingHubSkill() === skill.name}
- title={`Install ${skill.name}`}
+ title={`${translate("skills.install_btn")} ${skill.name}`}
>
- {installingHubSkill() === skill.name ? "Installing" : "Add"}
+ {installingHubSkill() === skill.name ? translate("skills.installing") : translate("skills.add")}
)}
@@ -797,7 +797,7 @@ export default function SkillsView(props: SkillsViewProps) {
- Capability setup
+ {translate("skills.capability_setup")}
{(item) => (
@@ -896,14 +896,14 @@ export default function SkillsView(props: SkillsViewProps) {
disabled={!selectedDirty() || props.busy}
onClick={() => void saveSelectedSkill()}
>
- Save
+ {translate("skills.save")}
- Close
+ {translate("skills.close")}
@@ -916,7 +916,7 @@ export default function SkillsView(props: SkillsViewProps) {
Loading… }
+ fallback={{translate("skills.loading")}}
>
Paste a skill bundle URL, preview it, then install.
+{translate("skills.install_link_desc")}
openwork).",
+ "identities.workspace_id_required": "Workspace ID is required to manage identities. Reconnect with a workspace URL (for example: /w/<workspace-id>) or select a workspace mapped on this host.",
+ "identities.tab_general": "General",
+ "identities.tab_advanced": "Advanced",
+ "identities.worker_online": "Worker online",
+ "identities.worker_unavailable": "Worker unavailable",
+ "identities.worker_offline": "Worker offline",
+ "identities.status_channels": "Channels",
+ "identities.status_messages_today": "Messages today",
+ "identities.status_last_activity": "Last activity",
+ "identities.available_channels": "Available channels",
+ "identities.telegram": "Telegram",
+ "identities.telegram_description": "Create a Telegram bot that anyone can message. Great for personal automations and external contacts.",
+ "identities.slack": "Slack",
+ "identities.slack_description": "Your worker appears as a bot in Slack channels. Team members can message it directly or mention it in threads.",
+ "identities.connected": "Connected",
+ "identities.status_active": "Active",
+ "identities.status_stopped": "Stopped",
+ "identities.configured": "configured",
+ "identities.channel_on": "On",
+ "identities.channel_off": "Off",
+ "identities.quick_setup": "Quick setup",
+ "identities.telegram_step1": "Open @BotFather and run /newbot.",
+ "identities.telegram_step2": "Copy the bot token and paste it below.",
+ "identities.telegram_step3": "Connect, then send /start to your bot to activate the chat.",
+ "identities.bot_token": "Bot token",
+ "identities.telegram_token_placeholder": "Paste Telegram bot token from @BotFather",
+ "identities.enabled": "Enabled",
+ "identities.connect_telegram": "Connect Telegram",
+ "identities.connecting": "Connecting...",
+ "identities.open_telegram_bot": "Open @{username} in Telegram",
+ "identities.slack_hint": "Connect your Slack workspace to let team members interact with this worker in channels and DMs.",
+ "identities.app_token": "App token",
+ "identities.connect_slack": "Connect Slack",
+ "identities.message_routing": "Message routing",
+ "identities.message_routing_description": "Control which conversations go to which workspace folder. Messages are routed to the worker's default folder unless you set up rules here.",
+ "identities.default_routing": "Default routing",
+ "identities.all_channels": "All channels",
+ "identities.routing_advanced_hint": "Advanced: reply with /dir <path> in Slack/Telegram to override the directory for a specific chat (limited to this workspace root).",
+ "identities.agent_behavior": "Messaging agent behavior",
+ "identities.agent_behavior_hint": "One file per workspace. Add optional first line @agent <id> to route via a specific OpenCode agent.",
+ "identities.active_scope": "Active scope: workspace · status: {loaded} · selected agent: {selected}",
+ "identities.loading_agent": "Loading agent file...",
+ "identities.agent_not_found": "Agent file not found in this workspace yet.",
+ "identities.agent_placeholder": "Add messaging behavior instructions for opencodeRouter here...",
+ "identities.reload": "Reload",
+ "identities.create_default_file": "Create default file",
+ "identities.save_behavior": "Save behavior",
+ "identities.saving": "Saving...",
+ "identities.unsaved_changes": "Unsaved changes",
+ "identities.send_test_message": "Send test message",
+ "identities.send_test_hint": "Validate outbound wiring. Use a peer ID for direct send, or leave peer ID empty to fan out by bindings in a directory.",
+ "identities.peer_id": "Peer ID (optional)",
+ "identities.directory": "Directory (optional)",
+ "identities.auto_bind": "Auto-bind peer to directory on direct send",
+ "identities.message": "Message",
+ "identities.test_message_placeholder": "Test message content",
+ "identities.sending": "Sending...",
+ "identities.disconnect": "Disconnect",
+ "identities.status_label": "Status",
+ "identities.identities_label": "Identities",
+ "identities.status_unavailable": "Unavailable",
+ "identities.status_unknown": "Unknown",
+ "identities.status_running": "Running",
+ "identities.status_offline": "Offline",
+ "identities.time_just_now": "Just now",
+ "identities.time_minutes_ago": "{minutes}m ago",
+ "identities.time_hours_ago": "{hours}h ago",
+ "identities.time_days_ago": "{days}d ago",
+ "identities.msg_agent_created": "Created default messaging agent file.",
+ "identities.msg_agent_saved": "Saved messaging behavior.",
+ "identities.error_file_changed": "File changed remotely. Reload and save again.",
+ "identities.msg_dispatched": "Dispatched {sent}/{attempted} messages.",
+ "identities.error_worker_scope_unavailable": "Worker scope unavailable.",
+ "identities.error_worker_scope_unavailable_long": "Worker scope unavailable. Reconnect using a worker URL or switch to a known worker.",
+ "identities.error_reconnect_failed": "Reconnect failed. Check OpenWork URL/token and try again.",
+ "identities.msg_reconnected_refreshing": "Reconnected. Refreshing worker state...",
+ "identities.msg_reconnected": "Reconnected.",
+ "identities.msg_saved_pending": "Saved (pending apply).",
+ "identities.msg_saved": "Saved.",
+ "identities.error_save_failed": "Failed to save.",
+ "identities.msg_deleted_pending": "Deleted (pending apply).",
+ "identities.msg_deleted": "Deleted.",
+ "identities.error_delete_failed": "Failed to delete.",
+ "identities.msg_saved_username": "Saved (@{username})",
+ "identities.error_health_unavailable": "OpenCodeRouter health unavailable ({status})",
+ "identities.error_telegram_unavailable": "Telegram identities unavailable.",
+ "identities.error_slack_unavailable": "Slack identities unavailable.",
+
+ "scheduled.never": "Never",
+ "scheduled.custom_schedule": "Custom schedule",
+ "scheduled.every_hour": "Every hour",
+ "scheduled.every_n_hours": "Every {n} hours",
+ "scheduled.every_day_at": "Every day at {time}",
+ "scheduled.weekdays_at": "Weekdays at {time}",
+ "scheduled.weekends_at": "Weekends at {time}",
+ "scheduled.at_time": "At {time}",
+ "scheduled.days_at_time": "{days} at {time}",
+ "scheduled.day_sun": "Sun",
+ "scheduled.day_mon": "Mon",
+ "scheduled.day_tue": "Tue",
+ "scheduled.day_wed": "Wed",
+ "scheduled.day_thu": "Thu",
+ "scheduled.day_fri": "Fri",
+ "scheduled.day_sat": "Sat",
+ "scheduled.label_command": "Command",
+ "scheduled.label_prompt": "Prompt",
+ "scheduled.label_task": "Task",
+ "scheduled.no_prompt_command": "No prompt or command found.",
+ "scheduled.status_not_run": "Not run yet",
+ "scheduled.status_running": "Running",
+ "scheduled.status_success": "Success",
+ "scheduled.status_failed": "Failed",
+ "scheduled.template_daily_planning": "Daily planning brief",
+ "scheduled.template_daily_planning_desc": "Build a focused plan from your tasks and calendar.",
+ "scheduled.template_daily_planning_prompt": "Review my pending tasks and calendar, then draft a practical plan for today with top priorities and one follow-up reminder.",
+ "scheduled.template_inbox_zero": "Inbox zero helper",
+ "scheduled.template_inbox_zero_desc": "Summarize unread messages and draft short replies.",
+ "scheduled.template_inbox_zero_prompt": "Summarize unread inbox messages, suggest priority order, and draft concise reply options for the top conversations.",
+ "scheduled.template_meeting_prep": "Meeting prep notes",
+ "scheduled.template_meeting_prep_desc": "Generate prep bullets for tomorrow's meetings.",
+ "scheduled.template_meeting_prep_prompt": "Prepare meeting briefs for tomorrow with context, talking points, and questions to unblock decisions.",
+ "scheduled.template_weekly_wins": "Weekly wins recap",
+ "scheduled.template_weekly_wins_desc": "Create a Friday recap of wins, blockers, and next steps.",
+ "scheduled.template_weekly_wins_prompt": "Summarize the week into wins, blockers, and clear next steps I can share with the team.",
+ "scheduled.template_learning_digest": "Learning digest",
+ "scheduled.template_learning_digest_desc": "Turn saved links and notes into a weekly digest.",
+ "scheduled.template_learning_digest_prompt": "Collect my saved links and notes, then draft a weekly learning digest with key ideas and follow-up actions.",
+ "scheduled.template_habit_checkin": "Habit check-in",
+ "scheduled.template_habit_checkin_desc": "Run a quick accountability check through the day.",
+ "scheduled.template_habit_checkin_prompt": "Ask me for a quick progress check-in, capture blockers, and suggest one concrete next action.",
+ "scheduled.run": "Run",
+ "scheduled.delete": "Delete",
+ "scheduled.run_context": "Run context",
+ "scheduled.source": "Source: {source}",
+ "scheduled.last_run": "Last run {time}",
+ "scheduled.created": "Created {time}",
+ "scheduled.agent": "Agent {agent}",
+ "scheduled.model": "Model {model}",
+ "scheduled.server_unavailable": "OpenWork server unavailable. Connect to sync scheduled tasks.",
+ "scheduled.desktop_required": "Scheduled tasks require the desktop app.",
+ "scheduled.windows_not_supported": "Scheduler is not supported on Windows yet.",
+ "scheduled.desc_remote": "Automations that run on a schedule from the connected OpenWork server.",
+ "scheduled.desc_local": "Automations that run on a schedule from this device.",
+ "scheduled.from_server": "From OpenWork server",
+ "scheduled.from_local": "From local scheduler",
+ "scheduled.server": "OpenWork server",
+ "scheduled.local": "Local",
+ "scheduled.remote_instance": "Remote instance",
+ "scheduled.launchd_systemd": "Launchd or systemd",
+ "scheduled.server_unavailable_short": "OpenWork server unavailable",
+ "scheduled.desktop_only": "Desktop-only",
+ "scheduled.delete_desc_remote": "This removes the schedule and deletes the job definition from the connected OpenWork server.",
+ "scheduled.delete_desc_local": "This removes the schedule and deletes the job definition from your machine.",
+ "scheduled.not_synced": "Not synced yet",
+ "scheduled.delete_failed": "Failed to delete job.",
+ "scheduled.refreshing": "Refreshing",
+ "scheduled.refresh": "Refresh",
+ "scheduled.new_automation": "New automation",
+ "scheduled.automations": "Automations",
+ "scheduled.beta": "Beta",
+ "scheduled.no_automations": "No automations yet. Pick a template or create your own automation prompt.",
+ "scheduled.explore_more": "Explore more",
+ "scheduled.delete_confirm_title": "Delete automation?",
+ "scheduled.deleting": "Deleting",
+ "scheduled.create_modal_title": "Create automation",
+ "scheduled.create_modal_desc": "Automations are scheduled by running a prompt in a new thread. We’ll prefill a prompt for you to send.",
+ "scheduled.name": "Name",
+ "scheduled.projects": "Projects",
+ "scheduled.choose_folder": "Choose a folder",
+ "scheduled.schedule": "Schedule",
+ "scheduled.daily": "Daily",
+ "scheduled.interval": "Interval",
+ "scheduled.every": "Every",
+ "scheduled.hours": "hours",
+ "scheduled.view_docs": "View scheduler docs",
+ "scheduled.cancel": "Cancel",
+ "scheduled.create": "Create",
+ "scheduled.run_now_prompt": "Run this automation now: {name}.\nSchedule: {schedule}.",
+ "scheduled.run_command_prompt": "Run this automation now: {name}.\nSchedule: {schedule}.\n\nRun the following command:\n{cmd}{workdirHint}",
+ "scheduled.prompt_construct": "Schedule a job{name} with cron \"{schedule}\" to {prompt}{workdir}",
+ "scheduled.run_from": " Run from {workdir}.",
+ "scheduled.named": " named \"{name}\"",
+
+ // ==================== Settings New ====================
+ "settings.messaging.title": "Messaging",
+ "settings.messaging.description": "Manage Telegram/Slack identities and bindings in the",
+ "settings.messaging.identities_link": "Identities",
+ "settings.messaging.tab": "tab.",
+ "settings.providers.title": "Providers",
+ "settings.providers.description": "Connect services for models and tools.",
+ "settings.providers.connect": "Connect provider",
+ "settings.providers.loading": "Loading providers...",
+ "settings.providers.summary.unavailable": "Connect to OpenCode to load providers.",
+ "settings.providers.summary.available": "{available} available",
+ "settings.providers.summary.connected": "{connected} connected · {available} available",
+ "settings.providers.api_keys_hint": "API keys are stored locally by OpenCode. Use /models to pick a default.",
+ "settings.appearance.title": "Appearance",
+ "settings.appearance.description": "Customize window appearance.",
+ "settings.appearance.hide_titlebar": "Hide titlebar",
+ "settings.appearance.hide_titlebar_hint": "Hide the window titlebar. Useful for tiling window managers on Linux (Hyprland, i3, sway).",
+ "settings.devtools.title": "Devtools",
+ "settings.devtools.description": "Sidecar health, capabilities, and audit trail.",
+ "settings.devtools.versions": "Versions",
+ "settings.devtools.versions_description": "Sidecar + desktop build info.",
+ "settings.devtools.opencode_engine": "OpenCode engine",
+ "settings.devtools.opencode_engine_description": "Local execution sidecar.",
+ "settings.devtools.orchestrator": "Orchestrator daemon",
+ "settings.devtools.orchestrator_description": "Workspace orchestration layer.",
+ "settings.devtools.opencode_sdk": "OpenCode SDK",
+ "settings.devtools.opencode_sdk_description": "UI connection diagnostics.",
+ "settings.devtools.openwork_server": "OpenWork server",
+ "settings.devtools.openwork_server_description": "Config and approvals sidecar.",
+ "settings.devtools.opencode_router": "OpenCodeRouter sidecar",
+ "settings.devtools.opencode_router_description": "Messaging bridge service.",
+ "settings.devtools.diagnostics": "OpenWork server diagnostics",
+ "settings.devtools.capabilities": "OpenWork server capabilities",
+ "settings.devtools.audit_log": "Audit log",
+ "settings.devtools.no_audit_entries": "No audit entries yet.",
+ "settings.engine.title": "Engine",
+ "settings.engine.description": "Choose how OpenCode runs locally.",
+ "settings.engine.source": "Engine source",
+ "settings.engine.bundled": "Bundled (recommended)",
+ "settings.engine.system": "System install (PATH)",
+ "settings.engine.custom": "Custom binary",
+ "settings.engine.bundled_hint": "Bundled engine is the most reliable option. Use System install only if you manage OpenCode yourself.",
+ "settings.engine.custom_label": "Custom OpenCode binary",
+ "settings.engine.custom_choose": "Choose",
+ "settings.engine.custom_clear": "Clear",
+ "settings.engine.custom_hint": "Use this to point OpenWork at a local OpenCode build (e.g. your fork). Applies next time the engine starts or reloads.",
+ "settings.engine.runtime": "Engine runtime",
+ "settings.engine.runtime_direct": "Direct (OpenCode)",
+ "settings.engine.runtime_orchestrator": "OpenWork Orchestrator",
+ "settings.engine.runtime_hint": "Applies the next time the engine starts or reloads.",
+ "settings.reset_recovery.title": "Reset & Recovery",
+ "settings.reset_recovery.description": "Clear data or restart the setup flow.",
+ "settings.tab.general": "General",
+ "settings.tab.model": "Model",
+ "settings.tab.advanced": "Advanced",
+ "settings.tab.debug": "Debug",
+ "settings.stop_local_server": "Stop local server",
+ "settings.disconnect_server": "Disconnect server",
+ "settings.reconnect_server": "Reconnect server",
+ "settings.reconnecting": "Reconnecting...",
+ "settings.restart": "Restart",
+ "settings.restarting": "Restarting...",
+ "settings.stop": "Stop",
+ "settings.clear": "Clear",
+ "settings.last_stdout": "Last stdout",
+ "settings.last_stderr": "Last stderr",
+ "settings.last_error": "Last error",
+ "settings.last_attempt": "Last attempt: {time}",
+ "settings.reason": "Reason: {reason}",
+ "settings.metrics.healthy": "Healthy: {ms}ms",
+ "settings.metrics.load_sessions": "Load sessions: {ms}ms",
+ "settings.metrics.pending_permissions": "Pending permissions: {ms}ms",
+ "settings.metrics.providers": "Providers: {ms}ms",
+ "settings.metrics.total": "Total: {ms}ms",
+ "settings.diagnostics_unavailable": "Diagnostics unavailable.",
+ "settings.capabilities_unavailable": "Capabilities unavailable. Connect with a client token.",
+ "settings.started": "Started: {time}",
+ "settings.read_only": "Read-only: {value}",
+ "settings.approval": "Approval: {mode} ({ms}ms)",
+ "settings.workspaces_count": "Workspaces: {count}",
+ "settings.active_workspace": "Active workspace: {id}",
+ "settings.config_path": "Config path: {path}",
+ "settings.token_source_client": "Token source: {source}",
+ "settings.token_source_host": "Host token source: {source}",
+ "settings.updates_auto_download": "Auto-update",
+ "settings.updates_auto_download_hint": "Download updates automatically (prompts to restart)",
+ "settings.docker_containers": "OpenWork Docker containers",
+ "settings.docker_containers_hint": "Force-remove Docker containers launched by OpenWork (sandbox + local dev stacks).",
+ "settings.workspace_debug_events": "Workspace debug events",
+ "settings.delete_containers": "Delete containers",
+ "settings.removing_containers": "Removing containers...",
+
+ // ==================== Session New ====================
+ "session.search_tooltip": "Search conversation (Ctrl/Cmd+F)",
+ "session.search_aria": "Search conversation",
+ "session.undo_tooltip": "Undo last message",
+ "session.redo_tooltip": "Redo last reverted message",
+ "session.actions_tooltip": "Session actions",
+ "session.select_session_tooltip": "Select a session to manage it",
+ "session.delete_title": "Delete session",
+ "session.delete_modal_title": "Delete session?",
+ "session.delete_modal_message": "This will permanently delete \"{title}\" and its messages.",
+ "session.delete_modal_message_default": "This will permanently delete the selected session and its messages.",
+ "session.show_earlier_messages": "Show {count} earlier message{plural}",
+ "session.jump_to_latest": "Jump to latest",
+ "session.toast_no_undo": "Nothing to undo yet.",
+ "session.toast_undo_success": "Reverted the last user message.",
+ "session.toast_no_redo": "Nothing to redo.",
+ "session.toast_redo_success": "Restored the reverted message.",
+ "session.toast_undo_failed": "Failed to undo",
+ "session.toast_redo_failed": "Failed to redo",
+ "session.toast_stopping": "Stopping the run...",
+ "session.toast_stopped": "Stopped.",
+ "session.toast_retrying": "Trying again...",
+ "session.toast_no_retry": "Nothing to retry yet",
+ "session.toast_no_session": "No session selected",
+ "session.toast_session_deleted": "Session deleted",
+ "session.toast_delete_failed": "Failed to delete session",
+ "session.toast_file_open_unavailable": "File open is unavailable for remote workers.",
+ "session.toast_file_open_desktop": "File open is available in the desktop app.",
+ "session.toast_pick_worker": "Pick a worker to open files.",
+ "session.toast_auth_started": "Auth flow started",
+ "session.toast_auth_failed": "Auth failed",
+ "session.toast_api_key_saved": "API key saved",
+ "session.toast_api_key_failed": "Failed to save API key",
+ "session.toast_upload_connect": "Connect to the OpenWork server to upload inbox files.",
+ "session.toast_uploading": "Uploading {label} to inbox...",
+ "session.toast_uploaded": "Uploaded to inbox.",
+ "session.toast_uploaded_summary": "Uploaded to inbox: {summary}",
+ "session.toast_upload_failed": "Inbox upload failed",
+ "session.toast_open_failed": "Unable to open file",
+ "session.toast_load_agents_failed": "Failed to load agents",
+ "session.toast_relative_only": "Only worker-relative files can be opened here.",
+ "session.toast_markdown_only": "Only markdown files can be edited here right now.",
+ "session.toast_connect_failed": "Connect failed",
+ "session.run_status_sending": "Sending",
+ "session.run_status_retrying": "Retrying",
+ "session.run_status_responding": "Responding",
+ "session.run_status_thinking": "Thinking",
+ "session.run_status_failed": "Run failed",
+ "session.flyout_new_task": "New Task",
+ "session.flyout_file_modified": "File Modified",
+ "session.hero_title": "What do you want to do?",
+ "session.hero_description": "Pick a starting point or just type below.",
+ "session.search_placeholder": "Search in this chat",
+ "session.search_prev": "Prev",
+ "session.search_next": "Next",
+ "session.tasks_progress": "{completed} out of {total} tasks completed",
+ "session.attach_token_hint": "Add a server token to attach files.",
+ "session.attach_connect_hint": "Connect to OpenWork server to attach files.",
+ "session.status_delegating": "Delegating",
+ "session.status_planning": "Planning",
+ "session.status_gathering_context": "Gathering context",
+ "session.status_searching_codebase": "Searching codebase",
+ "session.status_searching_web": "Searching the web",
+ "session.status_writing_file": "Writing file",
+ "session.status_running_shell": "Running shell",
+ "session.status_working": "Working",
+ "session.status_thinking_about": "Thinking about {subject}",
+ "session.status_gathering_thoughts": "Gathering thoughts",
+ "session.status_tool": "Tool",
+ "session.status_reasoning": "Reasoning",
+ "session.status_draft": "Draft",
+
+ "dashboard.quick_start_browser": "Automate your browser",
+ "dashboard.quick_start_browser_desc": "Set up browser actions and run reliable web tasks from OpenWork.",
+ "dashboard.quick_start_soul": "Give me a soul",
+ "dashboard.quick_start_soul_desc": "Keep your goals and preferences across sessions with light scheduled check-ins.",
+ "dashboard.quick_start_soul_note": "Tradeoff: more autonomy can create extra background runs, but revert is one command.",
+ "session.search_no_matches": "No matches",
+ "session.composer_loading_commands": "Loading commands...",
+ "session.composer_no_commands": "No commands found.",
+ "session.attachment_image": "Image",
+ "session.attachment_file": "File",
+ "session.upload_to_inbox": "Upload to inbox",
+ "session.composer_remote_workspace": "Remote workspace",
+ "session.attachments_unavailable": "Attachments are unavailable.",
+ "session.attach_files": "Attach files",
+ "session.agent_label": "Agent",
+ "session.loading_agents": "Loading agents...",
+ "session.default_agent": "Default agent",
+ "session.thinking_effort": "Thinking effort",
+ "session.active_variant": "Active",
+ "session.send_button": "Send",
+ "session.stop_button": "Stop",
+ "session.toast_unsupported_type": "Unsupported attachment type.",
+ "session.toast_file_too_large": "{name} exceeds the 8MB limit.",
+ "session.toast_image_too_large": "{name} is too large after encoding. Try a smaller image.",
+ "session.toast_read_failed": "Failed to read attachment",
+ "session.toast_remote_drop_hint": "This is a remote worker. Sandboxes are remote too. To share files with it, upload them to the Inbox in the sidebar.",
+ "session.show_steps": "Show {count} step{plural}",
+ "session.step_running": "running",
+ "session.copy_message": "Copy message",
+ "session.skill_badge": "skill",
+ "session.artifacts_title": "Artifacts",
+ "session.artifacts_empty": "No artifacts yet.",
+ "session.artifacts_image_preview_soon": "(image preview coming soon)",
+ "session.artifacts_show_fewer": "Show fewer",
+ "session.artifacts_show_more": "Show {count} more",
+ // Context Panel
+ "session.context_title": "Context",
+ "session.working_files_empty": "None yet.",
+ "session.plugins_title": "Plugins",
+ "session.plugins_empty": "No plugins loaded.",
+ "session.mcp_title": "MCP",
+ "session.mcp_empty": "No MCP servers loaded.",
+ "session.mcp_status_connected": "Connected",
+ "session.mcp_status_disconnected": "Disconnected",
+ "session.mcp_status_needs_auth": "Needs auth",
+ "session.mcp_status_register": "Register client",
+ "session.mcp_status_failed": "Failed",
+ "session.mcp_status_disabled": "Disabled",
+ "session.skills_title": "Skills",
+ "session.skills_empty": "No skills loaded.",
+ "session.authorized_folders_title": "Authorized folders",
+
+ // Inbox Panel
+ "session.inbox_title": "Inbox",
+ "session.inbox_refresh_tooltip": "Refresh inbox",
+ "session.inbox_drop_hint": "Drop files here to upload",
+ "session.inbox_upload_disabled": "Connect to a worker to upload",
+ "session.inbox_uploading": "Uploading...",
+ "session.inbox_upload_cta": "Drop files or click to upload",
+ "session.inbox_helper_text": "Share files with your remote worker.",
+ "session.inbox_connect_hint": "Connect to see inbox files.",
+ "session.inbox_empty": "No inbox files yet.",
+ "session.inbox_copy_tooltip": "Copy inbox path",
+ "session.inbox_download_tooltip": "Download",
+ "session.inbox_showing_first": "Showing first {count}.",
+ "session.inbox_toast_connect_upload": "Connect to a worker to upload inbox files.",
+ "session.inbox_toast_uploading": "Uploading {label}...",
+ "session.inbox_toast_uploaded": "Uploaded to worker inbox.",
+ "session.inbox_toast_upload_failed": "Inbox upload failed",
+ "session.inbox_toast_copied": "Copied: {path}",
+ "session.inbox_toast_copy_failed": "Copy failed. Your browser may block clipboard access.",
+ "session.inbox_toast_connect_download": "Connect to a worker to download inbox files.",
+ "session.inbox_toast_missing_id": "Missing inbox item id.",
+ "session.inbox_toast_download_failed": "Download failed",
+ "session.inbox_toast_load_failed": "Failed to load inbox",
+
+ // Editor
+ "session.editor_default_title": "Artifact",
+ "session.editor_unsaved": "Unsaved",
+ "session.editor_reload_tooltip": "Reload from disk",
+ "session.editor_reload": "Reload",
+ "session.editor_save_tooltip": "Save (Ctrl/Cmd+S)",
+ "session.editor_saving": "Saving...",
+ "session.editor_save": "Save",
+ "session.editor_close": "Close",
+ "session.editor_connect_hint": "Connect to an OpenWork server worker to edit files.",
+ "session.editor_overwrite_prompt": "File changed since load. Overwrite anyway?",
+ "session.editor_overwrite": "Overwrite",
+ "session.editor_discard_prompt": "Discard unsaved changes and close?",
+ "session.editor_keep": "Keep",
+ "session.editor_discard": "Discard",
+ "session.editor_switch_prompt": "Switch to {path}",
+ "session.editor_discard_switch": "Discard & switch",
+ "session.editor_save_switch": "Save & switch",
+ "session.editor_aria_label": "Artifact editor",
+ "session.editor_toast_save_connect": "Cannot save: OpenWork server not connected",
+ "session.editor_toast_markdown_only": "Only markdown files are supported",
+ "session.editor_toast_save_failed": "Failed to save",
+ "session.editor_toast_reload_discard": "Discard changes to reload from disk (close and reopen), or save first.",
+ "session.editor_toast_load_failed": "Failed to load file",
+ "session.editor_toast_not_found": "File not found (workspace root or outbox).",
+
+ // Minimap
+ "session.minimap_user_msg": "User message {index}",
+ "session.minimap_agent_msg": "Agent message {index}",
+ "session.minimap_user": "User",
+ "session.minimap_agent": "Agent",
+ "sidebar.needs_attention": "Needs attention",
+ "sidebar.expand": "Expand",
+ "sidebar.collapse": "Collapse",
+ "sidebar.drag_to_reorder": "Drag to reorder",
+ "sidebar.add_new_workspace": "Add new workspace",
+ "session.variant_none": "None",
+ "session.variant_low": "Low",
+ "session.variant_medium": "Medium",
+ "session.variant_high": "High",
+ "session.variant_xhigh": "X-High",
+ "session.click_to_expand": "Click to expand pasted text",
+ "session.pasted_text": "[pasted text]",
+ "common.remove": "Remove",
+ "sidebar.no_workspaces": "No workspaces in this session yet. Add one to get started.",
+
+ // Dashboard Updates
+ "dashboard.update_ready_btn": "Update ready",
+ "dashboard.install_update_btn": "Install update",
+ "dashboard.downloading_btn": "Downloading",
+ "dashboard.downloading_percent_btn": "Downloading {percent}%",
+ "dashboard.update_available_btn": "Update available",
+
+ // Status Bar
+ "status_bar.opencode_label": "OpenCode Engine: {status}",
+ "status_bar.openwork_label": "OpenWork Server: {status}",
+ "status_bar.connected": "Connected",
+ "status_bar.not_connected": "Not connected",
+ "status_bar.ready": "Ready",
+ "status_bar.limited_access": "Limited access",
+ "status_bar.unavailable": "Unavailable",
+ "status_bar.messaging_unavailable": "Messaging bridge unavailable",
+ "status_bar.messaging_ready": "Messaging bridge ready",
+ "status_bar.messaging_setup": "Messaging bridge setup",
+ "status_bar.messaging_offline": "Messaging bridge offline",
+ "status_bar.tip_connect_slack": "Connect Slack",
+ "status_bar.tip_connect_telegram": "Connect Telegram",
+ "status_bar.tip_connect_notion": "Connect Notion MCP",
+ "status_bar.tip_providers": "Use your own models (OpenRouter, Anthropic, OpenAI)",
+ "status_bar.tip_label": "Tip",
+ "status_bar.settings": "Settings",
+
+ // Identities Updates
+ "identities.connected_count": "{count} connected",
+ "identities.not_set": "Not set",
+ "identities.telegram_peer_placeholder": "Telegram chat id (e.g. 123456789)",
+ "identities.slack_peer_placeholder": "Slack peer id (e.g. D12345678|thread_ts)",
+
+ // Skills Updates
+ "skills.worker_profile": "Worker profile",
+ "skills.worker_profile_desc": "Skills are the core abilities of this worker. Add from Hub or create new ones directly in chat.",
+ "skills.create_in_chat": "Create skill in chat",
+ "skills.stat_installed": "Installed",
+ "skills.stat_hub_available": "Hub available",
+ "skills.stat_skill_creator": "Skill creator",
+ "skills.stat_not_installed": "Not installed",
+ "skills.stat_mode": "Mode",
+ "skills.mode_local": "Local",
+ "skills.mode_server": "Server",
+ "skills.search_placeholder": "Search installed or hub skills",
+ "skills.new_skill": "New skill",
+ "skills.install_link": "Install from link",
+ "skills.install_link_hint": "Install a skill from a link",
+ "skills.no_hub_skills": "No hub skills available.",
+ "skills.from_hub": "From openwork-hub",
+ "skills.trigger_label": "Trigger: {trigger}",
+ "skills.installing": "Installing",
+ "skills.add": "Add",
+ "skills.save": "Save",
+ "skills.close": "Close",
+ "skills.loading": "Loading...",
+ "skills.share_link_title": "Share link",
+ "skills.share_link_desc": "Publish a public link. Anyone with the URL can install this skill.",
+ "skills.publisher_label": "Publisher: {url}",
+ "skills.publishing": "Publishing...",
+ "skills.create_link": "Create link",
+ "skills.copy_link": "Copy link",
+ "skills.done": "Done",
+ "skills.install_link_title": "Install from link",
+ "skills.install_link_desc": "Paste a skill bundle URL, preview it, then install.",
+ "skills.link_label": "Link",
+ "skills.preview_label": "Preview",
+ "skills.skill_label": "Skill: {name}",
+ "skills.conflict_warning": "A skill with this name is already installed.",
+ "skills.keep_both": "Keep both",
+ "skills.overwrite": "Overwrite",
+ "skills.install_btn": "Install",
+ "skills.installing_btn": "Installing...",
+ "skills.edit": "Edit",
+ "skills.install_title": "Install skills",
+ "skills.refresh_hub_hint": "Refresh hub catalog",
+ "skills.refresh_hub": "Refresh hub",
+ "skills.capability_setup": "Capability setup",
} as const;
diff --git a/packages/app/src/i18n/locales/zh.ts b/packages/app/src/i18n/locales/zh.ts
index dcd72e8c..a0528c1d 100644
--- a/packages/app/src/i18n/locales/zh.ts
+++ b/packages/app/src/i18n/locales/zh.ts
@@ -172,7 +172,6 @@ export default {
"session.rename_description": "更新此会话名称。",
"session.rename_label": "会话名称",
"session.rename_placeholder": "输入新的名称",
-
// ==================== Commands ====================
"commands.new": "新建",
"commands.empty_state": "保存提示词或命令,一键重复运行。",
@@ -222,7 +221,6 @@ export default {
"skills.import": "导入",
"skills.curated_packages": "精选包",
"skills.view": "查看",
- "skills.search_placeholder": "搜索包或列表(例如:claude、registry、community)",
"skills.no_matches": "没有匹配的精选包。尝试不同的搜索。",
"skills.install_package": "安装",
"skills.registry_notice": "发布到 OpenPackage 注册表(`opkg push`)目前需要身份验证。计划添加注册表搜索和精选列表同步。",
@@ -305,14 +303,31 @@ export default {
"plugins.add_hint": "添加 npm 包名称,例如 opencode-wakatime",
// ==================== MCP (Model Context Protocol) ====================
+ "mcp.apps_title": "应用",
+ "mcp.apps_subtitle": "连接您喜欢的工具,让 OpenWork 代表您使用它们。",
+ "mcp.app_connected": "个应用已连接",
+ "mcp.apps_connected": "个应用已连接",
"mcp.title": "MCP(测试版)",
"mcp.description": "MCP 服务器让您使用自己的凭据连接服务。",
"mcp.alpha_banner_title": "MCP 处于测试阶段,我们正在加强与 OpenCode 的 OAuth 集成。",
"mcp.alpha_banner_help": "如果您想帮忙,请提交 PR 并附上一个短视频,展示 OAuth 流程从端到端的工作。",
"mcp.mcps_title": "MCPs",
"mcp.connect_mcp_hint": "连接 MCP 服务器以扩展 OpenWork 的功能。",
+ "mcp.finish_setup": "只差一步",
+ "mcp.finish_setup_hint": "点击激活以完成应用连接。",
+ "mcp.activate_button": "激活",
"mcp.reload_banner_title": "需要重新加载",
"mcp.reload_banner_description": "更改需要快速重新加载以激活 MCP 工具。",
+ "mcp.reload_banner_description_blocked": "任务正在运行。请先停止任务,然后激活。",
+ "mcp.reload_banner_blocked_hint": "停止正在运行的任务以激活。",
+ "mcp.available_apps": "可用应用",
+ "mcp.one_click_connect": "一键连接",
+ "mcp.tap_to_connect": "点击连接",
+ "mcp.connected_badge": "已连接",
+ "mcp.your_apps": "您的应用",
+ "mcp.last_synced": "已同步",
+ "mcp.no_apps_yet": "尚未连接应用",
+ "mcp.no_apps_hint": "连接上方的一个应用以开始。",
"mcp.quick_connect_title": "快速连接",
"mcp.oauth_only_label": "OAuth + 本地",
"mcp.connected_status": "已连接",
@@ -326,6 +341,7 @@ export default {
"mcp.scope_project": "项目",
"mcp.scope_global": "全局",
"mcp.config_label": "配置",
+ "mcp.config_file": "配置文件",
"mcp.config_not_loaded": "尚未加载",
"mcp.open_file_label": "打开文件",
"mcp.reveal_in_finder": "在文件管理器中显示",
@@ -338,6 +354,8 @@ export default {
"mcp.alpha_warning": "MCP 处于测试阶段,我们正在加强与 OpenCode 的 OAuth 集成。",
"mcp.github_issue": "在 GitHub 上查看 issue #9510",
"mcp.contribution_guide": "如果您想帮忙,请提交 PR 并附上一个短视频,展示 OAuth 流程从端到端的工作。",
+ "mcp.advanced_settings": "高级设置",
+ "mcp.advanced_settings_hint": "手动编辑配置文件并管理连接。",
"mcp.hide_advanced": "隐藏高级设置",
"mcp.show_advanced": "显示高级设置",
"mcp.mcps_label": "MCPs",
@@ -387,18 +405,21 @@ export default {
"mcp.verify_connection": "验证连接",
"mcp.cli_guidance": "CLI 指南(从您的工作区运行)",
"mcp.config_locations": "配置可以位于 opencode.json、opencode.jsonc 或 .opencode/opencode.json。",
+ "mcp.app_details": "应用详情",
"mcp.details_title": "详情",
- "mcp.select_server": "选择服务器",
+ "mcp.select_app_hint": "选择一个应用以查看详情。",
"mcp.select_server_hint": "选择服务器以查看状态和配置。",
- "mcp.capabilities": "功能",
+ "mcp.connection_type": "连接",
+ "mcp.type_cloud": "云端(使用您的帐户登录)",
+ "mcp.type_local": "本地(在此设备上运行)",
"mcp.capabilities_label": "功能",
- "mcp.tools_enabled": "已启用工具",
+ "mcp.cap_tools": "AI 工具",
+ "mcp.cap_signin": "帐户登录",
"mcp.tools_enabled_label": "已启用工具",
- "mcp.oauth_ready": "OAuth 就绪",
"mcp.oauth_ready_label": "OAuth 就绪",
- "mcp.usage_hint": "在提示中使用 MCP 服务器名称来定位其工具。",
"mcp.usage_hint_text": "在提示中使用 MCP 服务器名称来定位其工具。",
- "mcp.next_steps": "后续步骤",
+ "mcp.issue_label": "问题",
+ "mcp.technical_details": "技术详情",
"mcp.next_steps_label": "后续步骤",
"mcp.reload_step": "添加服务器后重新加载引擎。",
"mcp.auth_step": "如果提示,为 OAuth 服务器运行 opencode mcp auth。",
@@ -408,6 +429,11 @@ export default {
"mcp.status_disabled": "已禁用",
"mcp.disconnected": "已断开",
"mcp.failed": "失败",
+ "mcp.friendly_status_ready": "就绪",
+ "mcp.friendly_status_needs_signin": "需要登录",
+ "mcp.friendly_status_paused": "已暂停",
+ "mcp.friendly_status_offline": "离线",
+ "mcp.friendly_status_issue": "问题",
"mcp.host_mode_only": "MCP 连接需要桌面应用。",
"mcp.pick_workspace_first": "先选择一个工作区文件夹。",
"mcp.desktop_required": "MCP 连接需要桌面应用。",
@@ -437,6 +463,17 @@ export default {
"mcp.auth.reload_engine_retry": "重新加载引擎并重试",
"mcp.auth.retry_now": "立即重试",
"mcp.auth.retry": "重试",
+ "mcp.auth.reload_before_oauth": "在开始 OAuth 之前,重新加载引擎以完成此 MCP 的设置。",
+ "mcp.auth.reload_notice": "通过重新加载引擎来完成设置以激活此 MCP。这是一个必需的步骤,不是错误。",
+ "mcp.auth.reload_blocked": "会话运行时暂停重新加载。停止运行以完成设置。",
+ "mcp.auth.reload_needed": "通过重新加载引擎完成设置,然后尝试再次连接。",
+ "mcp.auth.manual_finish_title": "远程服务器?",
+ "mcp.auth.manual_finish_hint": "粘贴回调 URL (localhost:19876) 或仅粘贴代码以完成连接。",
+ "mcp.auth.callback_label": "回调 URL 或代码",
+ "mcp.auth.callback_placeholder": "http://127.0.0.1:19876/mcp/oauth/callback?code=...",
+ "mcp.auth.complete_connection": "完成连接",
+ "mcp.auth.callback_invalid": "粘贴回调 URL 或 code 参数以完成 OAuth。",
+ "mcp.auth.port_forward_hint": "提示:如果需要,转发回调端口:ssh -L 19876:127.0.0.1:19876 user@host",
"mcp.auth.step1_title": "正在打开您的浏览器",
"mcp.auth.step1_description": "我们将自动启动 {server} 的登录流程。",
"mcp.auth.step2_title": "授权 OpenWork",
@@ -616,6 +653,7 @@ export default {
"reload.toast_warning": "重新加载可能会中断正在进行的会话或流程。",
"reload.toast_warning_active": "检测到活动运行,立即重新加载将会中断它们。",
"reload.toast_reload": "重新加载",
+ "reload.toast_reload_stopped": "重新加载并停止任务",
"reload.toast_reloading": "正在重新加载...",
"reload.toast_dismiss": "忽略",
"reload.toast_blocked_host": "仅本地工作区可重新加载。",
@@ -704,6 +742,10 @@ export default {
"onboarding.default_workspace_path": "~/OpenWork/Workspace",
"onboarding.authorize_folder": "授权文件夹",
"onboarding.choose_workspace_folder": "选择工作区文件夹",
+ "onboarding.import_label": "导入",
+ "onboarding.import_description": "使用现有的工作区配置。",
+ "onboarding.import_hint": "仅导入 `.opencode` 和 `opencode.json`。",
+ "onboarding.import_button": "导入配置",
// ==================== Common ====================
"common.alpha": "测试版",
@@ -729,6 +771,7 @@ export default {
// ==================== Status ====================
"status.connected": "已连接",
+ "status.limited": "受限",
"status.disconnected": "已断开",
"status.idle": "空闲",
"status.busy": "忙碌",
@@ -776,4 +819,684 @@ export default {
"app.error.command_name_template_required": "命令名称和指令为必填项。",
"app.error.workspace_commands_desktop": "命令需要桌面应用。",
"app.error.command_scope_unknown": "此命令无法在当前模式下管理。",
+
+ // ==================== Config ====================
+ "config.title": "工作区配置",
+ "config.subtitle": "这些设置影响当前工作区(共享、重载、机器人)。全局应用行为在设置中。",
+ "config.workspace_label": "工作区:",
+ "config.engine_reload_title": "引擎重载",
+ "config.engine_reload_subtitle": "重启此工作区的 OpenCode 服务器。",
+ "config.reload_now": "立即重载",
+ "config.reload_now_subtitle": "应用配置更新并重新连接会话。",
+ "config.reload_warning": "重载将停止活动任务。",
+ "config.reload_connect_hint": "连接到此工作区以重载。",
+ "config.reload_local_only": "重载仅适用于本地工作区或已连接的 OpenWork 服务器。",
+ "config.reloading": "正在重载...",
+ "config.reload_engine": "重载引擎",
+ "config.auto_reload_title": "自动重载(本地)",
+ "config.auto_reload_subtitle": "在代理/技能/命令/配置更改后自动重载(仅空闲时)。",
+ "config.auto_reload_desktop_only": "仅适用于桌面应用中的本地工作区。",
+ "config.resume_sessions_title": "自动重载后恢复会话",
+ "config.resume_sessions_subtitle": "如果在任务运行时排队重载,之后发送恢复消息。",
+ "config.enable_auto_reload_first": "请先启用自动重载",
+ "config.diagnostics_title": "诊断包",
+ "config.diagnostics_subtitle": "复制用于调试的运行时状态。",
+ "config.copied": "已复制",
+ "config.copy": "复制",
+ "config.sharing_title": "OpenWork 服务器共享",
+ "config.sharing_subtitle": "与受信任的设备共享这些详情。保持服务器在同一网络以获得最快设置。",
+ "config.status_offline": "离线",
+ "config.status_available": "可用",
+ "config.server_url_label": "OpenWork 服务器地址",
+ "config.mdns_hint": ".local 名称更容易记住,但可能无法在所有网络上解析。",
+ "config.ip_hint": "在同一 Wi-Fi 下使用本地 IP 以获得最快连接。",
+ "config.starting_server": "正在启动服务器...",
+ "config.access_token_label": "访问令牌",
+ "config.access_token_hint": "用于连接到此服务器的手机或笔记本电脑。",
+ "config.hide": "隐藏",
+ "config.show": "显示",
+ "config.server_token_label": "服务器令牌",
+ "config.server_token_hint": "保持私密。批准操作需要。",
+ "config.share_hint": "对于每个工作区的共享链接,请使用工作区菜单中的 共享...。",
+ "config.openwork_server_title": "OpenWork 服务器",
+ "config.openwork_server_subtitle": "连接到 OpenWork 服务器。使用服务器管理员提供的 URL 和访问令牌。",
+ "config.sync_hint": "同步技能、插件和命令需要 OpenWork 服务器连接。",
+ "config.identities_title": "消息身份",
+ "config.identities_subtitle": "在 身份 选项卡中管理 Telegram/Slack 身份和路由。",
+ "config.desktop_only_hint": "某些配置功能(本地服务器共享 + 消息桥接)需要桌面应用。",
+ "config.testing": "测试中...",
+ "config.test_connection": "测试连接",
+ "config.save": "保存",
+ "config.reset": "重置",
+ "config.testing_connection": "正在测试连接...",
+ "config.connection_status_updated": "连接状态已更新。",
+ "config.connection_success": "连接成功。",
+ "config.connection_failed_generic": "连接失败。",
+ "config.resolved_worker_url": "解析的工作区 URL:",
+ "config.worker_id": "工作区 ID:",
+ "config.not_set": "未设置",
+ "config.unavailable": "不可用",
+
+ // ==================== Dashboard New ====================
+ "dashboard.tab_automations": "自动化",
+ "dashboard.tab_skills": "技能",
+ "dashboard.tab_extensions": "扩展",
+ "dashboard.tab_identities": "身份",
+ "dashboard.tab_advanced": "高级",
+ "dashboard.tab_settings": "设置",
+ "dashboard.workspace_worker": "工作区",
+ "dashboard.workspace_sandbox": "沙盒",
+ "dashboard.workspace_remote": "远程",
+ "dashboard.workspace_local": "本地",
+ "dashboard.show_more": "显示更多",
+ "dashboard.show_more_count": "显示更多 {count} 个",
+ "dashboard.add_worker": "添加工作区",
+ "dashboard.new_worker": "新建工作区",
+ "dashboard.connect_remote": "连接远程",
+ "dashboard.import_config": "导入配置",
+ "dashboard.tasks_header": "任务",
+ "dashboard.tasks_error": "加载任务失败",
+ "dashboard.tasks_error_badge": "错误",
+ "dashboard.tasks_empty": "暂无任务。",
+ "dashboard.tasks_new": "+ 新建任务",
+ "dashboard.menu_edit_name": "编辑名称",
+ "dashboard.menu_share": "共享...",
+ "dashboard.menu_test_connection": "测试连接",
+ "dashboard.menu_edit_connection": "编辑连接",
+ "dashboard.menu_stop_sandbox": "停止沙盒",
+ "dashboard.menu_remove_worker": "移除工作区",
+ "dashboard.loading_tasks": "正在加载任务...",
+ "dashboard.update_ready": "更新就绪",
+ "dashboard.update_restart": "重启",
+ "dashboard.update_downloading": "下载中",
+ "dashboard.update_available": "可用更新",
+ "dashboard.update_ready_tooltip": "更新 {version} 已就绪。停止活动运行以重启。",
+ "dashboard.update_restart_tooltip": "重启以应用更新 {version}",
+ "dashboard.update_downloading_tooltip": "正在下载更新 {version}",
+ "dashboard.update_available_tooltip": "可用更新 {version}",
+ "dashboard.share_worker_url": "OpenWork 工作区 URL",
+ "dashboard.share_desktop_required": "需要桌面应用",
+ "dashboard.share_starting_server": "正在启动服务器...",
+ "dashboard.share_worker_hint": "用于连接到此工作区的手机或笔记本电脑。",
+ "dashboard.share_resolving_hint": "工作区 URL 正在解析;显示主机 URL 作为回退。",
+ "dashboard.share_host_hint": "用于连接到此主机的手机或笔记本电脑。",
+ "dashboard.share_token_advanced_hint": "在高级设置中设置令牌",
+ "dashboard.share_token_grant_hint": "此令牌授予对该主机上工作区的访问权限。",
+ "dashboard.share_opencode_url": "OpenCode 基础 URL",
+ "dashboard.share_directory": "目录",
+ "dashboard.share_auto": "(自动)",
+ "dashboard.share_direct_warning": "引擎运行时设置为直连。切换本地工作区可能会重启主机并断开客户端连接。重启后令牌可能会更改。",
+ "dashboard.export_local_desktop": "导出仅适用于桌面应用中的本地工作区。",
+ "dashboard.export_local_only": "导出仅支持本地工作区。",
+ "dashboard.export_desktop_only": "导出仅在桌面应用中可用。",
+ "dashboard.export_running": "导出已在运行。",
+ "dashboard.repairing_cache_btn": "正在修复缓存",
+ "dashboard.repair_cache_btn": "修复缓存",
+ "dashboard.nav_ids": "IDs",
+ // ==================== Extensions ====================
+ "extensions.title": "扩展",
+ "extensions.description": "Apps (MCP) 和 OpenCode 插件集中管理。",
+ "extensions.apps_connected": "{count} 个应用已连接",
+ "extensions.plugins_count": "{count} 个插件",
+ "extensions.tab_all": "全部",
+ "extensions.tab_apps": "Apps",
+ "extensions.tab_plugins": "插件",
+ "extensions.refresh": "刷新",
+ "extensions.section_apps": "Apps (MCP)",
+ "extensions.section_plugins": "插件 (OpenCode)",
+
+ // ==================== Identities ====================
+ "identities.title": "消息渠道",
+ "identities.repair_reconnect": "修复并重连",
+ "identities.refresh": "刷新",
+ "identities.description": "让人们通过消息应用联系您的 Worker。连接一个渠道,Worker 将自动读取并回复消息。",
+ "identities.workspace_scope": "工作区范围:{url}",
+ "identities.connect_host": "连接 OpenWork 服务器",
+ "identities.connect_host_hint": "当连接到 OpenWork 主机 (openwork) 时,身份可用。",
+ "identities.workspace_id_required": "管理身份需要工作区 ID。请使用工作区 URL(例如:/w/<workspace-id>)重新连接,或选择此主机上映射的工作区。",
+ "identities.tab_general": "常规",
+ "identities.tab_advanced": "高级",
+ "identities.worker_online": "Worker 在线",
+ "identities.worker_unavailable": "Worker 不可用",
+ "identities.worker_offline": "Worker 离线",
+ "identities.status_channels": "渠道",
+ "identities.status_messages_today": "今日消息",
+ "identities.status_last_activity": "最后活动",
+ "identities.available_channels": "可用渠道",
+ "identities.telegram": "Telegram",
+ "identities.telegram_description": "创建一个任何人都可以发送消息的 Telegram 机器人。非常适合个人自动化和外部联系人。",
+ "identities.slack": "Slack",
+ "identities.slack_description": "您的 Worker 在 Slack 频道中显示为机器人。团队成员可以直接发送消息或在话题中提及它。",
+ "identities.connected": "已连接",
+ "identities.status_active": "活跃",
+ "identities.status_stopped": "停止",
+ "identities.configured": "已配置",
+ "identities.channel_on": "开启",
+ "identities.channel_off": "关闭",
+ "identities.quick_setup": "快速设置",
+ "identities.telegram_step1": "打开 @BotFather 并运行 /newbot。",
+ "identities.telegram_step2": "复制机器人令牌并粘贴到下方。",
+ "identities.telegram_step3": "连接,然后向您的机器人发送 /start 以激活聊天。",
+ "identities.bot_token": "机器人令牌",
+ "identities.telegram_token_placeholder": "粘贴来自 @BotFather 的 Telegram 机器人令牌",
+ "identities.enabled": "已启用",
+ "identities.connect_telegram": "连接 Telegram",
+ "identities.connecting": "连接中...",
+ "identities.open_telegram_bot": "在 Telegram 中打开 @{username}",
+ "identities.slack_hint": "连接您的 Slack 工作区,让团队成员在频道和私信中与此 Worker 交互。",
+ "identities.app_token": "应用令牌",
+ "identities.connect_slack": "连接 Slack",
+ "identities.message_routing": "消息路由",
+ "identities.message_routing_description": "控制哪些对话进入哪个工作区文件夹。除非您在此处设置规则,否则消息将路由到 Worker 的默认文件夹。",
+ "identities.default_routing": "默认路由",
+ "identities.all_channels": "所有渠道",
+ "identities.routing_advanced_hint": "高级:在 Slack/Telegram 中回复 /dir <path> 以覆盖特定聊天的目录(仅限于此工作区根目录)。",
+ "identities.agent_behavior": "消息代理行为",
+ "identities.agent_behavior_hint": "每个工作区一个文件。添加可选的第一行 @agent <id> 以通过特定的 OpenCode 代理进行路由。",
+ "identities.active_scope": "活动范围:工作区 · 状态:{loaded} · 选定代理:{selected}",
+ "identities.loading_agent": "正在加载代理文件...",
+ "identities.agent_not_found": "在此工作区中尚未找到代理文件。",
+ "identities.agent_placeholder": "在此处为 opencodeRouter 添加消息行为指令...",
+ "identities.reload": "重新加载",
+ "identities.create_default_file": "创建默认文件",
+ "identities.save_behavior": "保存行为",
+ "identities.saving": "保存中...",
+ "identities.unsaved_changes": "未保存的更改",
+ "identities.send_test_message": "发送测试消息",
+ "identities.send_test_hint": "验证出站连接。使用对等 ID 进行直接发送,或留空对等 ID 以通过目录中的绑定进行扇出。",
+ "identities.peer_id": "对等 ID(可选)",
+ "identities.directory": "目录(可选)",
+ "identities.auto_bind": "直接发送时自动将对等端绑定到目录",
+ "identities.message": "消息",
+ "identities.test_message_placeholder": "测试消息内容",
+ "identities.sending": "发送中...",
+ "identities.disconnect": "断开连接",
+ "identities.status_label": "状态",
+ "identities.identities_label": "身份",
+ "identities.status_unavailable": "不可用",
+ "identities.status_unknown": "未知",
+ "identities.status_running": "运行中",
+ "identities.status_offline": "离线",
+ "identities.time_just_now": "刚刚",
+ "identities.time_minutes_ago": "{minutes}分钟前",
+ "identities.time_hours_ago": "{hours}小时前",
+ "identities.time_days_ago": "{days}天前",
+ "identities.msg_agent_created": "已创建默认消息代理文件。",
+ "identities.msg_agent_saved": "已保存消息行为。",
+ "identities.error_file_changed": "文件在远程已更改。请重新加载并再次保存。",
+ "identities.msg_dispatched": "已发送 {sent}/{attempted} 条消息。",
+ "identities.error_worker_scope_unavailable": "工作区范围不可用。",
+ "identities.error_worker_scope_unavailable_long": "工作区范围不可用。请使用工作区 URL 重连或切换到已知工作区。",
+ "identities.error_reconnect_failed": "重连失败。请检查 OpenWork URL/令牌并重试。",
+ "identities.msg_reconnected_refreshing": "已重连。正在刷新工作区状态...",
+ "identities.msg_reconnected": "已重连。",
+ "identities.msg_saved_pending": "已保存(等待应用)。",
+ "identities.msg_saved": "已保存。",
+ "identities.error_save_failed": "保存失败。",
+ "identities.msg_deleted_pending": "已删除(等待应用)。",
+ "identities.msg_deleted": "已删除。",
+ "identities.error_delete_failed": "删除失败。",
+ "identities.msg_saved_username": "已保存 (@{username})",
+ "identities.error_health_unavailable": "OpenCodeRouter 健康检查不可用 ({status})",
+ "identities.error_telegram_unavailable": "Telegram 身份不可用。",
+ "identities.error_slack_unavailable": "Slack 身份不可用。",
+
+ "scheduled.never": "从不",
+ "scheduled.custom_schedule": "自定义计划",
+ "scheduled.every_hour": "每小时",
+ "scheduled.every_n_hours": "每 {n} 小时",
+ "scheduled.every_day_at": "每天 {time}",
+ "scheduled.weekdays_at": "工作日 {time}",
+ "scheduled.weekends_at": "周末 {time}",
+ "scheduled.at_time": "在 {time}",
+ "scheduled.days_at_time": "{days} {time}",
+ "scheduled.day_sun": "周日",
+ "scheduled.day_mon": "周一",
+ "scheduled.day_tue": "周二",
+ "scheduled.day_wed": "周三",
+ "scheduled.day_thu": "周四",
+ "scheduled.day_fri": "周五",
+ "scheduled.day_sat": "周六",
+ "scheduled.label_command": "命令",
+ "scheduled.label_prompt": "提示词",
+ "scheduled.label_task": "任务",
+ "scheduled.no_prompt_command": "未找到提示词或命令。",
+ "scheduled.status_not_run": "尚未运行",
+ "scheduled.status_running": "运行中",
+ "scheduled.status_success": "成功",
+ "scheduled.status_failed": "失败",
+ "scheduled.template_daily_planning": "每日计划简报",
+ "scheduled.template_daily_planning_desc": "根据你的任务和日历构建重点计划。",
+ "scheduled.template_daily_planning_prompt": "查看我的待办任务和日历,然后起草一份今天的实用计划,包含首要任务和一个跟进提醒。",
+ "scheduled.template_inbox_zero": "收件箱清零助手",
+ "scheduled.template_inbox_zero_desc": "总结未读消息并起草简短回复。",
+ "scheduled.template_inbox_zero_prompt": "总结未读收件箱消息,建议优先级顺序,并为重要对话起草简明回复选项。",
+ "scheduled.template_meeting_prep": "会议准备笔记",
+ "scheduled.template_meeting_prep_desc": "为明天的会议生成准备要点。",
+ "scheduled.template_meeting_prep_prompt": "为明天的会议准备简报,包含背景、谈话要点和决策阻碍问题。",
+ "scheduled.template_weekly_wins": "每周成果回顾",
+ "scheduled.template_weekly_wins_desc": "创建周五回顾,包含成果、阻碍和下一步。",
+ "scheduled.template_weekly_wins_prompt": "总结本周成果、阻碍和明确的下一步行动,以便我与团队分享。",
+ "scheduled.template_learning_digest": "学习摘要",
+ "scheduled.template_learning_digest_desc": "将保存的链接和笔记转化为每周摘要。",
+ "scheduled.template_learning_digest_prompt": "收集我保存的链接和笔记,然后起草一份包含关键观点和后续行动的每周学习摘要。",
+ "scheduled.template_habit_checkin": "习惯检查",
+ "scheduled.template_habit_checkin_desc": "全天进行快速问责检查。",
+ "scheduled.template_habit_checkin_prompt": "向我发起快速进度检查,记录阻碍,并建议一个具体的下一步行动。",
+ "scheduled.run": "运行",
+ "scheduled.delete": "删除",
+ "scheduled.run_context": "运行上下文",
+ "scheduled.source": "来源:{source}",
+ "scheduled.last_run": "上次运行 {time}",
+ "scheduled.created": "创建于 {time}",
+ "scheduled.agent": "代理 {agent}",
+ "scheduled.model": "模型 {model}",
+ "scheduled.server_unavailable": "OpenWork 服务器不可用。连接以同步计划任务。",
+ "scheduled.desktop_required": "计划任务需要桌面应用。",
+ "scheduled.windows_not_supported": "Windows 暂不支持计划任务。",
+ "scheduled.desc_remote": "从连接的 OpenWork 服务器按计划运行的自动化。",
+ "scheduled.desc_local": "从此设备按计划运行的自动化。",
+ "scheduled.from_server": "来自 OpenWork 服务器",
+ "scheduled.from_local": "来自本地调度器",
+ "scheduled.server": "OpenWork 服务器",
+ "scheduled.local": "本地",
+ "scheduled.remote_instance": "远程实例",
+ "scheduled.launchd_systemd": "Launchd 或 systemd",
+ "scheduled.server_unavailable_short": "OpenWork 服务器不可用",
+ "scheduled.desktop_only": "仅限桌面",
+ "scheduled.delete_desc_remote": "这将移除计划并从连接的 OpenWork 服务器删除作业定义。",
+ "scheduled.delete_desc_local": "这将移除计划并从你的机器删除作业定义。",
+ "scheduled.not_synced": "尚未同步",
+ "scheduled.delete_failed": "删除作业失败。",
+ "scheduled.refreshing": "正在刷新",
+ "scheduled.refresh": "刷新",
+ "scheduled.new_automation": "新建自动化",
+ "scheduled.automations": "自动化",
+ "scheduled.beta": "测试版",
+ "scheduled.no_automations": "暂无自动化。选择一个模板或创建你自己的自动化提示词。",
+ "scheduled.explore_more": "探索更多",
+ "scheduled.delete_confirm_title": "删除自动化?",
+ "scheduled.deleting": "正在删除",
+ "scheduled.create_modal_title": "创建自动化",
+ "scheduled.create_modal_desc": "自动化通过在新线程中运行提示词来调度。我们将为你预填一个提示词以供发送。",
+ "scheduled.name": "名称",
+ "scheduled.projects": "项目",
+ "scheduled.choose_folder": "选择文件夹",
+ "scheduled.schedule": "计划",
+ "scheduled.daily": "每日",
+ "scheduled.interval": "间隔",
+ "scheduled.every": "每",
+ "scheduled.hours": "小时",
+ "scheduled.view_docs": "查看调度器文档",
+ "scheduled.cancel": "取消",
+ "scheduled.create": "创建",
+ "scheduled.run_now_prompt": "立即运行此自动化:{name}。\n计划:{schedule}。",
+ "scheduled.run_command_prompt": "立即运行此自动化:{name}。\n计划:{schedule}。\n\n运行以下命令:\n{cmd}{workdirHint}",
+ "scheduled.prompt_construct": "调度一个作业{name},cron 表达式为 \"{schedule}\",以执行 {prompt}{workdir}",
+ "scheduled.run_from": " 运行自 {workdir}。",
+ "scheduled.named": " 命名为 \"{name}\"",
+
+ // ==================== Settings New ====================
+ "settings.messaging.title": "消息",
+ "settings.messaging.description": "在",
+ "settings.messaging.identities_link": "身份",
+ "settings.messaging.tab": "选项卡中管理 Telegram/Slack 身份和绑定。",
+ "settings.providers.title": "提供商",
+ "settings.providers.description": "连接模型和工具的服务。",
+ "settings.providers.connect": "连接提供商",
+ "settings.providers.loading": "正在加载提供商...",
+ "settings.providers.summary.unavailable": "连接到 OpenCode 以加载提供商。",
+ "settings.providers.summary.available": "{available} 可用",
+ "settings.providers.summary.connected": "{connected} 已连接 · {available} 可用",
+ "settings.providers.api_keys_hint": "API 密钥由 OpenCode 本地存储。使用 /models 选择默认模型。",
+ "settings.appearance.title": "外观",
+ "settings.appearance.description": "自定义窗口外观。",
+ "settings.appearance.hide_titlebar": "隐藏标题栏",
+ "settings.appearance.hide_titlebar_hint": "隐藏窗口标题栏。适用于 Linux 上的平铺窗口管理器(Hyprland, i3, sway)。",
+ "settings.devtools.title": "开发者工具",
+ "settings.devtools.description": "Sidecar 健康状况、功能和审计日志。",
+ "settings.devtools.versions": "版本",
+ "settings.devtools.versions_description": "Sidecar + 桌面构建信息。",
+ "settings.devtools.opencode_engine": "OpenCode 引擎",
+ "settings.devtools.opencode_engine_description": "本地执行 sidecar。",
+ "settings.devtools.orchestrator": "Orchestrator 守护进程",
+ "settings.devtools.orchestrator_description": "工作区编排层。",
+ "settings.devtools.opencode_sdk": "OpenCode SDK",
+ "settings.devtools.opencode_sdk_description": "UI 连接诊断。",
+ "settings.devtools.openwork_server": "OpenWork 服务器",
+ "settings.devtools.openwork_server_description": "配置和审批 sidecar。",
+ "settings.devtools.opencode_router": "OpenCodeRouter sidecar",
+ "settings.devtools.opencode_router_description": "消息桥接服务。",
+ "settings.devtools.diagnostics": "OpenWork 服务器诊断",
+ "settings.devtools.capabilities": "OpenWork 服务器功能",
+ "settings.devtools.audit_log": "审计日志",
+ "settings.devtools.no_audit_entries": "暂无审计条目。",
+ "settings.engine.title": "引擎",
+ "settings.engine.description": "选择 OpenCode 在本地的运行方式。",
+ "settings.engine.source": "引擎来源",
+ "settings.engine.bundled": "内置(推荐)",
+ "settings.engine.system": "系统安装(PATH)",
+ "settings.engine.custom": "自定义二进制",
+ "settings.engine.bundled_hint": "内置引擎是最可靠的选项。仅当您自己管理 OpenCode 时才使用系统安装。",
+ "settings.engine.custom_label": "自定义 OpenCode 二进制",
+ "settings.engine.custom_choose": "选择",
+ "settings.engine.custom_clear": "清除",
+ "settings.engine.custom_hint": "使用此选项将 OpenWork 指向本地 OpenCode 构建(例如您的 fork)。在下次引擎启动或重新加载时生效。",
+ "settings.engine.runtime": "引擎运行时",
+ "settings.engine.runtime_direct": "直接(OpenCode)",
+ "settings.engine.runtime_orchestrator": "OpenWork Orchestrator",
+ "settings.engine.runtime_hint": "在下次引擎启动或重新加载时生效。",
+ "settings.reset_recovery.title": "重置与恢复",
+ "settings.reset_recovery.description": "清除数据或重新开始设置流程。",
+ "settings.tab.general": "常规",
+ "settings.tab.model": "模型",
+ "settings.tab.advanced": "高级",
+ "settings.tab.debug": "调试",
+ "settings.stop_local_server": "停止本地服务器",
+ "settings.disconnect_server": "断开服务器连接",
+ "settings.reconnect_server": "重新连接服务器",
+ "settings.reconnecting": "正在重新连接...",
+ "settings.restart": "重启",
+ "settings.restarting": "正在重启...",
+ "settings.stop": "停止",
+ "settings.clear": "清除",
+ "settings.last_stdout": "最新标准输出",
+ "settings.last_stderr": "最新标准错误",
+ "settings.last_error": "最新错误",
+ "settings.last_attempt": "上次尝试:{time}",
+ "settings.reason": "原因:{reason}",
+ "settings.metrics.healthy": "健康:{ms}ms",
+ "settings.metrics.load_sessions": "加载会话:{ms}ms",
+ "settings.metrics.pending_permissions": "待处理权限:{ms}ms",
+ "settings.metrics.providers": "提供商:{ms}ms",
+ "settings.metrics.total": "总计:{ms}ms",
+ "settings.diagnostics_unavailable": "诊断不可用。",
+ "settings.capabilities_unavailable": "功能不可用。请使用客户端令牌连接。",
+ "settings.started": "启动时间:{time}",
+ "settings.read_only": "只读:{value}",
+ "settings.approval": "审批:{mode} ({ms}ms)",
+ "settings.workspaces_count": "工作区数:{count}",
+ "settings.active_workspace": "活动工作区:{id}",
+ "settings.config_path": "配置路径:{path}",
+ "settings.token_source_client": "令牌来源:{source}",
+ "settings.token_source_host": "主机令牌来源:{source}",
+ "settings.updates_auto_download": "自动更新",
+ "settings.updates_auto_download_hint": "自动下载更新(提示重启)",
+ "settings.docker_containers": "OpenWork Docker 容器",
+ "settings.docker_containers_hint": "强制删除 OpenWork 启动的 Docker 容器(沙盒 + 本地开发堆栈)。",
+ "settings.workspace_debug_events": "工作区调试事件",
+ "settings.delete_containers": "删除容器",
+ "settings.removing_containers": "正在删除容器...",
+
+ // ==================== Session New ====================
+ "session.search_tooltip": "搜索对话 (Ctrl/Cmd+F)",
+ "session.search_aria": "搜索对话",
+ "session.undo_tooltip": "撤销上一条消息",
+ "session.redo_tooltip": "重做上一条撤销的消息",
+ "session.actions_tooltip": "会话操作",
+ "session.select_session_tooltip": "选择一个会话以管理它",
+ "session.delete_title": "删除会话",
+ "session.delete_modal_title": "删除会话?",
+ "session.delete_modal_message": "这将永久删除 \"{title}\" 及其消息。",
+ "session.delete_modal_message_default": "这将永久删除所选会话及其消息。",
+ "session.show_earlier_messages": "显示之前的 {count} 条消息",
+ "session.jump_to_latest": "跳转到最新",
+ "session.toast_no_undo": "暂无由于可撤销。",
+ "session.toast_undo_success": "已撤销上一条用户消息。",
+ "session.toast_no_redo": "暂无内容可重做。",
+ "session.toast_redo_success": "已恢复撤销的消息。",
+ "session.toast_undo_failed": "撤销失败",
+ "session.toast_redo_failed": "重做失败",
+ "session.toast_stopping": "正在停止运行...",
+ "session.toast_stopped": "已停止。",
+ "session.toast_retrying": "正在重试...",
+ "session.toast_no_retry": "暂无内容可重试",
+ "session.toast_no_session": "未选择会话",
+ "session.toast_session_deleted": "会话已删除",
+ "session.toast_delete_failed": "删除会话失败",
+ "session.toast_file_open_unavailable": "远程工作区无法打开文件。",
+ "session.toast_file_open_desktop": "打开文件仅在桌面应用中可用。",
+ "session.toast_pick_worker": "选择一个工作区以打开文件。",
+ "session.toast_auth_started": "认证流程已开始",
+ "session.toast_auth_failed": "认证失败",
+ "session.toast_api_key_saved": "API 密钥已保存",
+ "session.toast_api_key_failed": "保存 API 密钥失败",
+ "session.toast_upload_connect": "连接到 OpenWork 服务器以上传收件箱文件。",
+ "session.toast_uploading": "正在上传 {label} 到收件箱...",
+ "session.toast_uploaded": "已上传到收件箱。",
+ "session.toast_uploaded_summary": "已上传到收件箱:{summary}",
+ "session.toast_upload_failed": "收件箱上传失败",
+ "session.toast_open_failed": "无法打开文件",
+ "session.toast_load_agents_failed": "加载代理失败",
+ "session.toast_relative_only": "此处仅能打开工作区相关文件。",
+ "session.toast_markdown_only": "目前仅支持编辑 Markdown 文件。",
+ "session.toast_connect_failed": "连接失败",
+ "session.run_status_sending": "发送中",
+ "session.run_status_retrying": "重试中",
+ "session.run_status_responding": "响应中",
+ "session.run_status_thinking": "思考中",
+ "session.run_status_failed": "运行失败",
+ "session.flyout_new_task": "新任务",
+ "session.flyout_file_modified": "文件已修改",
+ "session.hero_title": "想做些什么?",
+ "session.hero_description": "选择一个起点或直接在下方输入。",
+ "session.search_placeholder": "在当前会话中搜索",
+ "session.search_prev": "上一个",
+ "session.search_next": "下一个",
+ "session.tasks_progress": "已完成 {completed}/{total} 个任务",
+ "session.attach_token_hint": "添加服务器令牌以附加文件。",
+ "session.attach_connect_hint": "连接到 OpenWork 服务器以附加文件。",
+ "session.status_delegating": "委派中",
+ "session.status_planning": "规划中",
+ "session.status_gathering_context": "收集上下文中",
+ "session.status_searching_codebase": "搜索代码库中",
+ "session.status_searching_web": "搜索网络中",
+ "session.status_writing_file": "写入文件中",
+ "session.status_running_shell": "运行 Shell 中",
+ "session.status_working": "工作中",
+ "session.status_thinking_about": "正在思考 {subject}",
+ "session.status_gathering_thoughts": "整理思路中",
+ "session.status_tool": "工具",
+ "session.status_reasoning": "推理中",
+ "session.status_draft": "草稿",
+
+ "dashboard.quick_start_browser": "自动化您的浏览器",
+ "dashboard.quick_start_browser_desc": "设置浏览器操作并从 OpenWork 运行可靠的 Web 任务。",
+ "dashboard.quick_start_soul": "赋予我灵魂",
+ "dashboard.quick_start_soul_desc": "通过轻量级计划检查,跨会话保持您的目标和偏好。",
+ "dashboard.quick_start_soul_note": "权衡:更多的自主权可能会产生额外的后台运行,但只需一个命令即可撤销。",
+ "session.search_no_matches": "无匹配",
+ "session.composer_loading_commands": "正在加载命令...",
+ "session.composer_no_commands": "未找到命令。",
+ "session.attachment_image": "图片",
+ "session.attachment_file": "文件",
+ "session.upload_to_inbox": "上传到收件箱",
+ "session.composer_remote_workspace": "远程工作区",
+ "session.attachments_unavailable": "附件不可用。",
+ "session.attach_files": "附加文件",
+ "session.agent_label": "代理",
+ "session.loading_agents": "正在加载代理...",
+ "session.default_agent": "默认代理",
+ "session.thinking_effort": "思考力度",
+ "session.active_variant": "当前",
+ "session.send_button": "发送",
+ "session.stop_button": "停止",
+ "session.toast_unsupported_type": "不支持的附件类型。",
+ "session.toast_file_too_large": "{name} 超过 8MB 限制。",
+ "session.toast_image_too_large": "{name} 编码后过大。请尝试更小的图片。",
+ "session.toast_read_failed": "读取附件失败",
+ "session.toast_remote_drop_hint": "这是一个远程工作区(沙盒也是远程的)。要与其共享文件,请上传到侧边栏的收件箱。",
+ "session.show_steps": "显示 {count} 个步骤",
+ "session.step_running": "运行中",
+ "session.copy_message": "复制消息",
+ "session.skill_badge": "技能",
+ "session.artifacts_title": "产物",
+ "session.artifacts_empty": "暂无产物。",
+ "session.artifacts_image_preview_soon": "(图片预览即将推出)",
+ "session.artifacts_show_fewer": "收起",
+ "session.artifacts_show_more": "显示更多 {count} 个",
+ // Context Panel
+ "session.context_title": "上下文",
+ "session.working_files_empty": "暂无。",
+ "session.plugins_title": "插件",
+ "session.plugins_empty": "未加载插件。",
+ "session.mcp_title": "MCP",
+ "session.mcp_empty": "未加载 MCP 服务器。",
+ "session.mcp_status_connected": "已连接",
+ "session.mcp_status_disconnected": "已断开",
+ "session.mcp_status_needs_auth": "需要认证",
+ "session.mcp_status_register": "注册客户端",
+ "session.mcp_status_failed": "失败",
+ "session.mcp_status_disabled": "已禁用",
+ "session.skills_title": "技能",
+ "session.skills_empty": "未加载技能。",
+ "session.authorized_folders_title": "授权文件夹",
+
+ // Inbox Panel
+ "session.inbox_title": "收件箱",
+ "session.inbox_refresh_tooltip": "刷新收件箱",
+ "session.inbox_drop_hint": "拖放文件到此处上传",
+ "session.inbox_upload_disabled": "连接到工作区以上传",
+ "session.inbox_uploading": "正在上传...",
+ "session.inbox_upload_cta": "拖放文件或点击上传",
+ "session.inbox_helper_text": "与您的远程工作区共享文件。",
+ "session.inbox_connect_hint": "连接以查看收件箱文件。",
+ "session.inbox_empty": "暂无收件箱文件。",
+ "session.inbox_copy_tooltip": "复制收件箱路径",
+ "session.inbox_download_tooltip": "下载",
+ "session.inbox_showing_first": "显示前 {count} 项。",
+ "session.inbox_toast_connect_upload": "连接到工作区以上传收件箱文件。",
+ "session.inbox_toast_uploading": "正在上传 {label}...",
+ "session.inbox_toast_uploaded": "已上传到工作区收件箱。",
+ "session.inbox_toast_upload_failed": "收件箱上传失败",
+ "session.inbox_toast_copied": "已复制:{path}",
+ "session.inbox_toast_copy_failed": "复制失败。您的浏览器可能会阻止剪贴板访问。",
+ "session.inbox_toast_connect_download": "连接到工作区以下载收件箱文件。",
+ "session.inbox_toast_missing_id": "缺少收件箱项目 ID。",
+ "session.inbox_toast_download_failed": "下载失败",
+ "session.inbox_toast_load_failed": "加载收件箱失败",
+
+ // Editor
+ "session.editor_default_title": "产物",
+ "session.editor_unsaved": "未保存",
+ "session.editor_reload_tooltip": "从磁盘重新加载",
+ "session.editor_reload": "重新加载",
+ "session.editor_save_tooltip": "保存 (Ctrl/Cmd+S)",
+ "session.editor_saving": "保存中...",
+ "session.editor_save": "保存",
+ "session.editor_close": "关闭",
+ "session.editor_connect_hint": "连接到 OpenWork 服务器工作区以编辑文件。",
+ "session.editor_overwrite_prompt": "文件自加载以来已更改。仍然覆盖?",
+ "session.editor_overwrite": "覆盖",
+ "session.editor_discard_prompt": "放弃未保存的更改并关闭?",
+ "session.editor_keep": "保留",
+ "session.editor_discard": "放弃",
+ "session.editor_switch_prompt": "切换到 {path}",
+ "session.editor_discard_switch": "放弃并切换",
+ "session.editor_save_switch": "保存并切换",
+ "session.editor_aria_label": "产物编辑器",
+ "session.editor_toast_save_connect": "无法保存:未连接 OpenWork 服务器",
+ "session.editor_toast_markdown_only": "仅支持 Markdown 文件",
+ "session.editor_toast_save_failed": "保存失败",
+ "session.editor_toast_reload_discard": "放弃更改以从磁盘重新加载(关闭并重新打开),或先保存。",
+ "session.editor_toast_load_failed": "加载文件失败",
+ "session.editor_toast_not_found": "文件未找到(工作区根目录或发件箱)。",
+
+ // Minimap
+ "session.minimap_user_msg": "用户消息 {index}",
+ "session.minimap_agent_msg": "代理消息 {index}",
+ "session.minimap_user": "用户",
+ "session.minimap_agent": "代理",
+ "sidebar.needs_attention": "需要注意",
+ "sidebar.expand": "展开",
+ "sidebar.collapse": "折叠",
+ "sidebar.drag_to_reorder": "拖动排序",
+ "sidebar.add_new_workspace": "添加新工作区",
+ "session.variant_none": "无",
+ "session.variant_low": "低",
+ "session.variant_medium": "中",
+ "session.variant_high": "高",
+ "session.variant_xhigh": "超高",
+ "session.click_to_expand": "点击展开粘贴的文本",
+ "session.pasted_text": "[粘贴的文本]",
+ "common.remove": "移除",
+ "sidebar.no_workspaces": "此会话中尚未添加工作区。添加一个以开始。",
+
+ // Dashboard Updates
+ "dashboard.update_ready_btn": "更新就绪",
+ "dashboard.install_update_btn": "安装更新",
+ "dashboard.downloading_btn": "正在下载",
+ "dashboard.downloading_percent_btn": "正在下载 {percent}%",
+ "dashboard.update_available_btn": "有可用更新",
+
+ // Status Bar
+ "status_bar.opencode_label": "OpenCode 引擎:{status}",
+ "status_bar.openwork_label": "OpenWork 服务器:{status}",
+ "status_bar.connected": "已连接",
+ "status_bar.not_connected": "未连接",
+ "status_bar.ready": "就绪",
+ "status_bar.limited_access": "受限访问",
+ "status_bar.unavailable": "不可用",
+ "status_bar.messaging_unavailable": "消息桥接不可用",
+ "status_bar.messaging_ready": "消息桥接就绪",
+ "status_bar.messaging_setup": "消息桥接设置",
+ "status_bar.messaging_offline": "消息桥接离线",
+ "status_bar.tip_connect_slack": "连接 Slack",
+ "status_bar.tip_connect_telegram": "连接 Telegram",
+ "status_bar.tip_connect_notion": "连接 Notion MCP",
+ "status_bar.tip_providers": "使用您自己的模型(OpenRouter, Anthropic, OpenAI)",
+ "status_bar.tip_label": "提示",
+ "status_bar.settings": "设置",
+
+ // Identities Updates
+ "identities.connected_count": "{count} 已连接",
+ "identities.not_set": "未设置",
+ "identities.telegram_peer_placeholder": "Telegram 聊天 ID (例如 123456789)",
+ "identities.slack_peer_placeholder": "Slack 对等 ID (例如 D12345678|thread_ts)",
+
+ // Skills Updates
+ "skills.worker_profile": "Worker 资料",
+ "skills.worker_profile_desc": "技能是此 Worker 的核心能力。从 Hub 添加或直接在聊天中创建新技能。",
+ "skills.create_in_chat": "在聊天中创建技能",
+ "skills.stat_installed": "已安装",
+ "skills.stat_hub_available": "Hub 可用",
+ "skills.stat_skill_creator": "技能创建器",
+ "skills.stat_not_installed": "未安装",
+ "skills.stat_mode": "模式",
+ "skills.mode_local": "本地",
+ "skills.mode_server": "服务器",
+ "skills.search_placeholder": "搜索已安装或 Hub 技能",
+ "skills.new_skill": "新建技能",
+ "skills.install_link": "从链接安装",
+ "skills.install_link_hint": "从链接安装技能",
+ "skills.no_hub_skills": "没有可用的 Hub 技能。",
+ "skills.from_hub": "来自 openwork-hub",
+ "skills.trigger_label": "触发器:{trigger}",
+ "skills.installing": "正在安装",
+ "skills.add": "添加",
+ "skills.save": "保存",
+ "skills.close": "关闭",
+ "skills.loading": "加载中...",
+ "skills.share_link_title": "分享链接",
+ "skills.share_link_desc": "发布公开链接。任何拥有该 URL 的人都可以安装此技能。",
+ "skills.publisher_label": "发布者:{url}",
+ "skills.publishing": "正在发布...",
+ "skills.create_link": "创建链接",
+ "skills.copy_link": "复制链接",
+ "skills.done": "完成",
+ "skills.install_link_title": "从链接安装",
+ "skills.install_link_desc": "粘贴技能包 URL,预览并安装。",
+ "skills.link_label": "链接",
+ "skills.preview_label": "预览",
+ "skills.skill_label": "技能:{name}",
+ "skills.conflict_warning": "已安装同名技能。",
+ "skills.keep_both": "保留两者",
+ "skills.overwrite": "覆盖",
+ "skills.install_btn": "安装",
+ "skills.installing_btn": "安装中...",
+ "skills.edit": "编辑",
+ "skills.install_title": "安装技能",
+ "skills.refresh_hub_hint": "刷新 Hub 目录",
+ "skills.refresh_hub": "刷新 Hub",
+ "skills.capability_setup": "能力设置",
} as const;