Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/app/src/components/windows-app-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
import { useCommand } from "@/context/command"
import { DESKTOP_MENU, desktopMenuVisible, type DesktopMenuAction, type DesktopMenuEntry } from "@/desktop-menu"
import { usePlatform } from "@/context/platform"
import { useLanguage } from "@/context/language"

export function WindowsAppMenu(props: {
command: ReturnType<typeof useCommand>
platform: ReturnType<typeof usePlatform>
variant?: "legacy" | "v2"
}) {
const language = useLanguage()
const t = language.t as (key: string) => string
let lastFocused: HTMLElement | undefined

const rememberFocus = () => {
Expand Down Expand Up @@ -79,15 +82,15 @@ export function WindowsAppMenu(props: {
<DropdownMenu.Group>
<DropdownMenu.GroupLabel class="desktop-app-menu-heading">OpenCode</DropdownMenu.GroupLabel>
{DESKTOP_MENU.filter((menu) => desktopMenuVisible(menu, "windows")).map((menu) => (
<DesktopMenuSubmenu label={menu.label}>
<DesktopMenuSubmenu label={t(menu.label)}>
{menu.items
?.filter((entry) => desktopMenuVisible(entry, "windows"))
.map((entry) =>
entry.type === "separator" ? (
<DropdownMenu.Separator />
) : (
<DesktopMenuItem
label={entry.label ?? ""}
label={t(entry.label ?? "")}
keybind={entry.command ? props.command.keybind(entry.command) : entry.accelerator?.windows}
disabled={entry.command ? commandDisabled(entry.command) : false}
onSelect={() => runEntry(entry)}
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/desktop-menu.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { DESKTOP_MENU } from "./desktop-menu"
describe("desktop menu", () => {
test("exports logs through the desktop command registry", () => {
const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter(
(item) => item.type === "item" && item.label === "Export Logs...",
(item) => item.type === "item" && item.label === "menu.help.exportLogs",
)

expect(items).toHaveLength(2)
expect(items).toHaveLength(1)
expect(items.every((item) => item.type === "item" && item.command === "logs.export" && !item.action)).toBe(true)
})
})
94 changes: 47 additions & 47 deletions packages/app/src/desktop-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ export type DesktopMenu = {
export const DESKTOP_MENU: DesktopMenu[] = [
{
id: "app",
label: "OpenCode",
label: "menu.app",
platforms: ["macos"],
items: [
{ type: "item", role: "about" },
{ type: "item", label: "Check for Updates...", action: "app.checkForUpdates", enabled: "updater" },
{ type: "item", label: "Settings", command: "settings.open", accelerator: { macos: "Cmd+," } },
{ type: "item", label: "Reload Webview", action: "view.reload" },
{ type: "item", label: "Restart", action: "app.relaunch" },
{ type: "item", label: "Export Logs...", command: "logs.export" },
{ type: "item", label: "menu.app.checkUpdates", action: "app.checkForUpdates", enabled: "updater" },
{ type: "item", label: "menu.app.settings", command: "settings.open", accelerator: { macos: "Cmd+," } },
{ type: "item", label: "menu.app.reloadWebview", action: "view.reload" },
{ type: "item", label: "menu.app.restart", action: "app.relaunch" },
{ type: "item", label: "menu.app.exportLogs", command: "logs.export" },
{ type: "separator" },
{ type: "item", role: "hide" },
{ type: "item", role: "hideOthers" },
Expand All @@ -91,46 +91,46 @@ export const DESKTOP_MENU: DesktopMenu[] = [
},
{
id: "file",
label: "File",
label: "menu.file",
items: [
{
type: "item",
label: "New Session",
label: "menu.file.newSession",
command: "session.new",
accelerator: { macos: "Shift+Cmd+S" },
},
{ type: "item", label: "Open Project...", command: "project.open", accelerator: { macos: "Cmd+O" } },
{ type: "item", label: "menu.file.openProject", command: "project.open", accelerator: { macos: "Cmd+O" } },
{
type: "item",
label: "Settings",
label: "menu.file.settings",
command: "settings.open",
accelerator: { windows: "Ctrl+," },
platforms: ["windows"],
},
{
type: "item",
label: "New Window",
label: "menu.file.newWindow",
action: "window.new",
accelerator: { macos: "Cmd+Shift+N", windows: "Ctrl+Shift+N" },
},
{ type: "separator" },
{ type: "item", label: "Close Window", action: "window.close", role: "close" },
{ type: "item", label: "menu.file.closeWindow", action: "window.close", role: "close" },
],
},
{
id: "edit",
label: "Edit",
label: "menu.edit",
items: [
{ type: "item", label: "Undo", action: "edit.undo", role: "undo", accelerator: { windows: "Ctrl+Z" } },
{ type: "item", label: "Redo", action: "edit.redo", role: "redo", accelerator: { windows: "Ctrl+Y" } },
{ type: "item", label: "menu.edit.undo", action: "edit.undo", role: "undo", accelerator: { windows: "Ctrl+Z" } },
{ type: "item", label: "menu.edit.redo", action: "edit.redo", role: "redo", accelerator: { windows: "Ctrl+Y" } },
{ type: "separator" },
{ type: "item", label: "Cut", action: "edit.cut", role: "cut", accelerator: { windows: "Ctrl+X" } },
{ type: "item", label: "Copy", action: "edit.copy", role: "copy", accelerator: { windows: "Ctrl+C" } },
{ type: "item", label: "Paste", action: "edit.paste", role: "paste", accelerator: { windows: "Ctrl+V" } },
{ type: "item", label: "Delete", action: "edit.delete" },
{ type: "item", label: "menu.edit.cut", action: "edit.cut", role: "cut", accelerator: { windows: "Ctrl+X" } },
{ type: "item", label: "menu.edit.copy", action: "edit.copy", role: "copy", accelerator: { windows: "Ctrl+C" } },
{ type: "item", label: "menu.edit.paste", action: "edit.paste", role: "paste", accelerator: { windows: "Ctrl+V" } },
{ type: "item", label: "menu.edit.delete", action: "edit.delete" },
{
type: "item",
label: "Select All",
label: "menu.edit.selectAll",
action: "edit.selectAll",
role: "selectAll",
accelerator: { windows: "Ctrl+A" },
Expand All @@ -139,79 +139,79 @@ export const DESKTOP_MENU: DesktopMenu[] = [
},
{
id: "view",
label: "View",
label: "menu.view",
items: [
{ type: "item", label: "Toggle Sidebar", command: "sidebar.toggle" },
{ type: "item", label: "Toggle Terminal", command: "terminal.toggle", accelerator: { macos: "Ctrl+`" } },
{ type: "item", label: "Toggle File Tree", command: "fileTree.toggle" },
{ type: "item", label: "menu.view.toggleSidebar", command: "sidebar.toggle" },
{ type: "item", label: "menu.view.toggleTerminal", command: "terminal.toggle", accelerator: { macos: "Ctrl+`" } },
{ type: "item", label: "menu.view.toggleFileTree", command: "fileTree.toggle" },
{ type: "separator" },
{ type: "item", label: "Reload", action: "view.reload", role: "reload" },
{ type: "item", label: "Toggle Developer Tools", action: "view.toggleDevTools", role: "toggleDevTools" },
{ type: "item", label: "menu.view.reload", action: "view.reload", role: "reload" },
{ type: "item", label: "menu.view.toggleDevTools", action: "view.toggleDevTools", role: "toggleDevTools" },
{ type: "separator" },
{
type: "item",
label: "Actual Size",
label: "menu.view.actualSize",
action: "view.resetZoom",
role: "resetZoom",
accelerator: { windows: "Ctrl+0" },
},
{ type: "item", label: "Zoom In", action: "view.zoomIn", role: "zoomIn", accelerator: { windows: "Ctrl++" } },
{ type: "item", label: "Zoom Out", action: "view.zoomOut", role: "zoomOut", accelerator: { windows: "Ctrl+-" } },
{ type: "item", label: "menu.view.zoomIn", action: "view.zoomIn", role: "zoomIn", accelerator: { windows: "Ctrl++" } },
{ type: "item", label: "menu.view.zoomOut", action: "view.zoomOut", role: "zoomOut", accelerator: { windows: "Ctrl+-" } },
{ type: "separator" },
{ type: "item", label: "Toggle Full Screen", action: "view.toggleFullscreen", role: "togglefullscreen" },
{ type: "item", label: "menu.view.toggleFullScreen", action: "view.toggleFullscreen", role: "togglefullscreen" },
],
},
{
id: "go",
label: "Go",
label: "menu.go",
items: [
{ type: "item", label: "Back", command: "common.goBack", accelerator: { macos: "Cmd+[" } },
{ type: "item", label: "Forward", command: "common.goForward", accelerator: { macos: "Cmd+]" } },
{ type: "item", label: "menu.go.back", command: "common.goBack", accelerator: { macos: "Cmd+[" } },
{ type: "item", label: "menu.go.forward", command: "common.goForward", accelerator: { macos: "Cmd+]" } },
{ type: "separator" },
{ type: "item", label: "Previous Session", command: "session.previous", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Session", command: "session.next", accelerator: { macos: "Option+Down" } },
{ type: "item", label: "menu.go.previousSession", command: "session.previous", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "menu.go.nextSession", command: "session.next", accelerator: { macos: "Option+Down" } },
{ type: "separator" },
{
type: "item",
label: "Previous Project",
label: "menu.go.previousProject",
command: "project.previous",
accelerator: { macos: "Cmd+Option+Up" },
},
{
type: "item",
label: "Next Project",
label: "menu.go.nextProject",
command: "project.next",
accelerator: { macos: "Cmd+Option+Down" },
},
],
},
{
id: "window",
label: "Window",
label: "menu.window",
role: "windowMenu",
items: [
{ type: "item", label: "Minimize", action: "window.minimize" },
{ type: "item", label: "Maximize", action: "window.toggleMaximize" },
{ type: "item", label: "menu.window.minimize", action: "window.minimize" },
{ type: "item", label: "menu.window.maximize", action: "window.toggleMaximize" },
{ type: "separator" },
{ type: "item", label: "Close Window", action: "window.close" },
{ type: "item", label: "menu.window.closeWindow", action: "window.close" },
],
},
{
id: "help",
label: "Help",
label: "menu.help",
items: [
{ type: "item", label: "OpenCode Documentation", href: "https://opencode.ai/docs" },
{ type: "item", label: "Support Forum", href: "https://discord.com/invite/opencode" },
{ type: "item", label: "Export Logs...", command: "logs.export" },
{ type: "item", label: "menu.help.documentation", href: "https://opencode.ai/docs" },
{ type: "item", label: "menu.help.supportForum", href: "https://discord.com/invite/opencode" },
{ type: "item", label: "menu.help.exportLogs", command: "logs.export" },
{ type: "separator" },
{
type: "item",
label: "Share Feedback",
label: "menu.help.shareFeedback",
href: "https://github.com/anomalyco/opencode/issues/new?template=feature_request.yml",
},
{
type: "item",
label: "Report a Bug",
label: "menu.help.reportBug",
href: "https://github.com/anomalyco/opencode/issues/new?template=bug_report.yml",
},
],
Expand Down
60 changes: 60 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,4 +1076,64 @@ export const dict = {
"workspace.reset.archived.one": "1 session will be archived.",
"workspace.reset.archived.many": "{{count}} sessions will be archived.",
"workspace.reset.note": "This will reset the workspace to match the default branch.",

"menu.app": "OpenCode",
"menu.file": "File",
"menu.edit": "Edit",
"menu.view": "View",
"menu.go": "Go",
"menu.window": "Window",
"menu.help": "Help",

"menu.file.newSession": "New Session",
"menu.file.openProject": "Open Project...",
"menu.file.settings": "Settings",
"menu.file.newWindow": "New Window",
"menu.file.closeWindow": "Close Window",

"menu.edit.undo": "Undo",
"menu.edit.redo": "Redo",
"menu.edit.cut": "Cut",
"menu.edit.copy": "Copy",
"menu.edit.paste": "Paste",
"menu.edit.delete": "Delete",
"menu.edit.selectAll": "Select All",

"menu.view.toggleSidebar": "Toggle Sidebar",
"menu.view.toggleTerminal": "Toggle Terminal",
"menu.view.toggleFileTree": "Toggle File Tree",
"menu.view.reload": "Reload",
"menu.view.toggleDevTools": "Toggle Developer Tools",
"menu.view.actualSize": "Actual Size",
"menu.view.zoomIn": "Zoom In",
"menu.view.zoomOut": "Zoom Out",
"menu.view.toggleFullScreen": "Toggle Full Screen",

"menu.go.back": "Back",
"menu.go.forward": "Forward",
"menu.go.previousSession": "Previous Session",
"menu.go.nextSession": "Next Session",
"menu.go.previousProject": "Previous Project",
"menu.go.nextProject": "Next Project",

"menu.window.minimize": "Minimize",
"menu.window.maximize": "Maximize",
"menu.window.closeWindow": "Close Window",

"menu.help.documentation": "OpenCode Documentation",
"menu.help.supportForum": "Support Forum",
"menu.help.exportLogs": "Export Logs...",
"menu.help.shareFeedback": "Share Feedback",
"menu.help.reportBug": "Report a Bug",

"menu.app.about": "About OpenCode",
"menu.app.checkUpdates": "Check for Updates...",
"menu.app.settings": "Settings",
"menu.app.reloadWebview": "Reload Webview",
"menu.app.restart": "Restart",
"menu.app.exportLogs": "Export Logs...",
"menu.app.hide": "Hide OpenCode",
"menu.app.hideOthers": "Hide Others",
"menu.app.showAll": "Show All",
"menu.app.quit": "Quit OpenCode",
}
60 changes: 60 additions & 0 deletions packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,64 @@ export const dict = {
"error.childStore.persistedProjectIconCreateFailed": "创建持久化项目图标失败",
"error.childStore.storeCreateFailed": "创建存储失败",
"terminal.connectionLost.abnormalClose": "WebSocket 异常关闭:{{code}}",

"menu.app": "OpenCode",
"menu.file": "文件",
"menu.edit": "编辑",
"menu.view": "视图",
"menu.go": "转到",
"menu.window": "窗口",
"menu.help": "帮助",

"menu.file.newSession": "新建会话",
"menu.file.openProject": "打开项目...",
"menu.file.settings": "设置",
"menu.file.newWindow": "新建窗口",
"menu.file.closeWindow": "关闭窗口",

"menu.edit.undo": "撤销",
"menu.edit.redo": "重做",
"menu.edit.cut": "剪切",
"menu.edit.copy": "复制",
"menu.edit.paste": "粘贴",
"menu.edit.delete": "删除",
"menu.edit.selectAll": "全选",

"menu.view.toggleSidebar": "切换侧边栏",
"menu.view.toggleTerminal": "切换终端",
"menu.view.toggleFileTree": "切换文件树",
"menu.view.reload": "重新加载",
"menu.view.toggleDevTools": "切换开发者工具",
"menu.view.actualSize": "实际大小",
"menu.view.zoomIn": "放大",
"menu.view.zoomOut": "缩小",
"menu.view.toggleFullScreen": "切换全屏",

"menu.go.back": "后退",
"menu.go.forward": "前进",
"menu.go.previousSession": "上一个会话",
"menu.go.nextSession": "下一个会话",
"menu.go.previousProject": "上一个项目",
"menu.go.nextProject": "下一个项目",

"menu.window.minimize": "最小化",
"menu.window.maximize": "最大化",
"menu.window.closeWindow": "关闭窗口",

"menu.help.documentation": "OpenCode 文档",
"menu.help.supportForum": "支持论坛",
"menu.help.exportLogs": "导出日志...",
"menu.help.shareFeedback": "分享反馈",
"menu.help.reportBug": "报告 Bug",

"menu.app.about": "关于 OpenCode",
"menu.app.checkUpdates": "检查更新...",
"menu.app.settings": "设置",
"menu.app.reloadWebview": "重新加载页面",
"menu.app.restart": "重启",
"menu.app.exportLogs": "导出日志...",
"menu.app.hide": "隐藏 OpenCode",
"menu.app.hideOthers": "隐藏其他",
"menu.app.showAll": "显示全部",
"menu.app.quit": "退出 OpenCode",
} satisfies Partial<Record<Keys, string>>
Loading
Loading