feat(ui): localize UI strings
Converts hardcoded UI copy to i18n keys across the app, adds global translation for non-component modules, and splits the English catalog into feature modules with duplicate-key detection.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { createContext, createMemo, createSignal, onMount, useContext } from "solid-js"
|
||||
import { createContext, createEffect, createMemo, createSignal, onCleanup, onMount, useContext } from "solid-js"
|
||||
import type { ParentComponent } from "solid-js"
|
||||
import { useConfig } from "../../stores/preferences"
|
||||
import { enMessages } from "./messages/en"
|
||||
import { enMessages } from "./messages/en/index"
|
||||
|
||||
type Messages = Record<string, string>
|
||||
|
||||
export type TranslateParams = Record<string, unknown>
|
||||
|
||||
export type Locale = "en"
|
||||
|
||||
const SUPPORTED_LOCALES: readonly Locale[] = ["en"] as const
|
||||
@@ -57,9 +59,25 @@ function interpolate(template: string, params?: Record<string, unknown>): string
|
||||
})
|
||||
}
|
||||
|
||||
function translateFrom(messages: Messages, key: string, params?: TranslateParams): string {
|
||||
const current = messages[key]
|
||||
const fallback = enMessages[key as keyof typeof enMessages]
|
||||
const template = current ?? fallback ?? key
|
||||
return interpolate(template, params)
|
||||
}
|
||||
|
||||
const [globalRevision, setGlobalRevision] = createSignal(0)
|
||||
const initialGlobalLocale: Locale = detectNavigatorLocale() ?? "en"
|
||||
let globalMessages: Messages = messagesByLocale[initialGlobalLocale]
|
||||
|
||||
export function tGlobal(key: string, params?: TranslateParams): string {
|
||||
globalRevision()
|
||||
return translateFrom(globalMessages, key, params)
|
||||
}
|
||||
|
||||
export interface I18nContextValue {
|
||||
locale: () => Locale
|
||||
t: (key: string, params?: Record<string, unknown>) => string
|
||||
t: (key: string, params?: TranslateParams) => string
|
||||
}
|
||||
|
||||
const I18nContext = createContext<I18nContextValue>()
|
||||
@@ -68,6 +86,8 @@ export const I18nProvider: ParentComponent = (props) => {
|
||||
const { preferences } = useConfig()
|
||||
const [detectedLocale, setDetectedLocale] = createSignal<Locale>("en")
|
||||
|
||||
const previousMessages = globalMessages
|
||||
|
||||
onMount(() => {
|
||||
const detected = detectNavigatorLocale()
|
||||
if (detected) setDetectedLocale(detected)
|
||||
@@ -80,13 +100,20 @@ export const I18nProvider: ParentComponent = (props) => {
|
||||
|
||||
const messages = createMemo<Messages>(() => messagesByLocale[locale()])
|
||||
|
||||
function t(key: string, params?: Record<string, unknown>): string {
|
||||
const current = messages()[key]
|
||||
const fallback = enMessages[key as keyof typeof enMessages]
|
||||
const template = current ?? fallback ?? key
|
||||
return interpolate(template, params)
|
||||
function t(key: string, params?: TranslateParams): string {
|
||||
return translateFrom(messages(), key, params)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
globalMessages = messages()
|
||||
setGlobalRevision((value) => value + 1)
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
globalMessages = previousMessages
|
||||
setGlobalRevision((value) => value + 1)
|
||||
})
|
||||
|
||||
const value: I18nContextValue = {
|
||||
locale,
|
||||
t,
|
||||
|
||||
6
packages/ui/src/lib/i18n/messages/en/advancedSettings.ts
Normal file
6
packages/ui/src/lib/i18n/messages/en/advancedSettings.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const advancedSettingsMessages = {
|
||||
"advancedSettings.title": "Advanced Settings",
|
||||
"advancedSettings.environmentVariables.title": "Environment Variables",
|
||||
"advancedSettings.environmentVariables.subtitle": "Applied whenever a new OpenCode instance starts",
|
||||
"advancedSettings.actions.close": "Close",
|
||||
} as const
|
||||
29
packages/ui/src/lib/i18n/messages/en/app.ts
Normal file
29
packages/ui/src/lib/i18n/messages/en/app.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export const appMessages = {
|
||||
"app.launchError.title": "Unable to launch OpenCode",
|
||||
"app.launchError.description": "We couldn't start the selected OpenCode binary. Review the error output below or choose a different binary from Advanced Settings.",
|
||||
"app.launchError.binaryPathLabel": "Binary path",
|
||||
"app.launchError.errorOutputLabel": "Error output",
|
||||
"app.launchError.openAdvancedSettings": "Open Advanced Settings",
|
||||
"app.launchError.close": "Close",
|
||||
"app.launchError.closeTitle": "Close (Esc)",
|
||||
"app.launchError.fallbackMessage": "Failed to launch workspace",
|
||||
|
||||
"app.stopInstance.confirmMessage": "Stop OpenCode instance? This will stop the server.",
|
||||
"app.stopInstance.title": "Stop instance",
|
||||
"app.stopInstance.confirmLabel": "Stop",
|
||||
"app.stopInstance.cancelLabel": "Keep running",
|
||||
|
||||
"emptyState.logoAlt": "CodeNomad logo",
|
||||
"emptyState.brandTitle": "CodeNomad",
|
||||
"emptyState.tagline": "Select a folder to start coding with AI",
|
||||
"emptyState.actions.selectFolder": "Select Folder",
|
||||
"emptyState.actions.selecting": "Selecting...",
|
||||
"emptyState.keyboardShortcut": "Keyboard shortcut: {shortcut}",
|
||||
"emptyState.examples": "Examples: {example}",
|
||||
"emptyState.multipleInstances": "You can have multiple instances of the same folder",
|
||||
|
||||
"releases.upgradeRequired.title": "Upgrade required",
|
||||
"releases.upgradeRequired.message.withVersion": "Update to CodeNomad {version} to use the latest UI.",
|
||||
"releases.upgradeRequired.message.noVersion": "Update CodeNomad to use the latest UI.",
|
||||
"releases.upgradeRequired.action.getUpdate": "Get update",
|
||||
} as const
|
||||
160
packages/ui/src/lib/i18n/messages/en/commands.ts
Normal file
160
packages/ui/src/lib/i18n/messages/en/commands.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
export const commandMessages = {
|
||||
"commandPalette.title": "Command Palette",
|
||||
"commandPalette.description": "Search and execute commands",
|
||||
"commandPalette.searchPlaceholder": "Type a command or search...",
|
||||
"commandPalette.empty": "No commands found for \"{query}\"",
|
||||
"commandPalette.category.customCommands": "Custom Commands",
|
||||
"commandPalette.category.instance": "Instance",
|
||||
"commandPalette.category.session": "Session",
|
||||
"commandPalette.category.agentModel": "Agent & Model",
|
||||
"commandPalette.category.inputFocus": "Input & Focus",
|
||||
"commandPalette.category.system": "System",
|
||||
"commandPalette.category.other": "Other",
|
||||
|
||||
"commands.newInstance.label": "New Instance",
|
||||
"commands.newInstance.description": "Open folder picker to create new instance",
|
||||
"commands.newInstance.keywords": "folder, project, workspace",
|
||||
|
||||
"commands.closeInstance.label": "Close Instance",
|
||||
"commands.closeInstance.description": "Stop current instance's server",
|
||||
"commands.closeInstance.keywords": "stop, quit, close",
|
||||
|
||||
"commands.nextInstance.label": "Next Instance",
|
||||
"commands.nextInstance.description": "Cycle to next instance tab",
|
||||
"commands.nextInstance.keywords": "switch, navigate",
|
||||
|
||||
"commands.previousInstance.label": "Previous Instance",
|
||||
"commands.previousInstance.description": "Cycle to previous instance tab",
|
||||
"commands.previousInstance.keywords": "switch, navigate",
|
||||
|
||||
"commands.newSession.label": "New Session",
|
||||
"commands.newSession.description": "Create a new parent session",
|
||||
"commands.newSession.keywords": "create, start",
|
||||
|
||||
"commands.closeSession.label": "Close Session",
|
||||
"commands.closeSession.description": "Close current parent session",
|
||||
"commands.closeSession.keywords": "close, stop",
|
||||
|
||||
"commands.scrubSessions.label": "Scrub Sessions",
|
||||
"commands.scrubSessions.description": "Remove empty sessions, subagent sessions that have completed their primary task, and extraneous forked sessions.",
|
||||
"commands.scrubSessions.keywords": "cleanup, blank, empty, sessions, remove, delete, scrub",
|
||||
|
||||
"commands.instanceInfo.label": "Instance Info",
|
||||
"commands.instanceInfo.description": "Open the instance overview for logs and status",
|
||||
"commands.instanceInfo.keywords": "info, logs, console, output",
|
||||
|
||||
"commands.nextSession.label": "Next Session",
|
||||
"commands.nextSession.description": "Cycle to next session tab",
|
||||
"commands.nextSession.keywords": "switch, navigate",
|
||||
|
||||
"commands.previousSession.label": "Previous Session",
|
||||
"commands.previousSession.description": "Cycle to previous session tab",
|
||||
"commands.previousSession.keywords": "switch, navigate",
|
||||
|
||||
"commands.compactSession.label": "Compact Session",
|
||||
"commands.compactSession.description": "Summarize and compact the current session",
|
||||
"commands.compactSession.keywords": "summarize, compress",
|
||||
"commands.compactSession.errorFallback": "Failed to compact session",
|
||||
"commands.compactSession.alert.title": "Compact failed",
|
||||
"commands.compactSession.alert.message": "Compact failed: {message}",
|
||||
|
||||
"commands.undoLastMessage.label": "Undo Last Message",
|
||||
"commands.undoLastMessage.description": "Revert the last message",
|
||||
"commands.undoLastMessage.keywords": "revert, undo",
|
||||
"commands.undoLastMessage.none.title": "No actions to undo",
|
||||
"commands.undoLastMessage.none.message": "Nothing to undo",
|
||||
"commands.undoLastMessage.failed.title": "Undo failed",
|
||||
"commands.undoLastMessage.failed.message": "Failed to revert message",
|
||||
|
||||
"commands.openModelSelector.label": "Open Model Selector",
|
||||
"commands.openModelSelector.description": "Choose a different model",
|
||||
"commands.openModelSelector.keywords": "model, llm, ai",
|
||||
|
||||
"commands.selectModelVariant.label": "Select Model Variant",
|
||||
"commands.selectModelVariant.description": "Choose a thinking effort for the current model",
|
||||
"commands.selectModelVariant.keywords": "variant, thinking, reasoning, effort",
|
||||
|
||||
"commands.openAgentSelector.label": "Open Agent Selector",
|
||||
"commands.openAgentSelector.description": "Choose a different agent",
|
||||
"commands.openAgentSelector.keywords": "agent, mode",
|
||||
|
||||
"commands.clearInput.label": "Clear Input",
|
||||
"commands.clearInput.description": "Clear the prompt textarea",
|
||||
"commands.clearInput.keywords": "clear, reset",
|
||||
|
||||
"commands.thinkingBlocks.label.show": "Show Thinking Blocks",
|
||||
"commands.thinkingBlocks.label.hide": "Hide Thinking Blocks",
|
||||
"commands.thinkingBlocks.description": "Show/hide AI thinking process",
|
||||
"commands.thinkingBlocks.keywords": "thinking, reasoning, toggle, show, hide",
|
||||
|
||||
"commands.timelineToolCalls.label.show": "Show Timeline Tool Calls",
|
||||
"commands.timelineToolCalls.label.hide": "Hide Timeline Tool Calls",
|
||||
"commands.timelineToolCalls.description": "Toggle tool call entries in the message timeline",
|
||||
"commands.timelineToolCalls.keywords": "timeline, tool, toggle",
|
||||
|
||||
"commands.common.expanded": "Expanded",
|
||||
"commands.common.collapsed": "Collapsed",
|
||||
"commands.common.visible": "Visible",
|
||||
"commands.common.hidden": "Hidden",
|
||||
"commands.common.enabled": "Enabled",
|
||||
"commands.common.disabled": "Disabled",
|
||||
|
||||
"commands.thinkingBlocksDefault.label": "Thinking Blocks Default · {state}",
|
||||
"commands.thinkingBlocksDefault.description": "Toggle whether thinking blocks start expanded",
|
||||
"commands.thinkingBlocksDefault.keywords": "thinking, reasoning, expand, collapse, default",
|
||||
|
||||
"commands.diffViewSplit.label": "Use Split Diff View",
|
||||
"commands.diffViewSplit.description": "Display tool-call diffs side-by-side",
|
||||
"commands.diffViewSplit.keywords": "diff, split, view",
|
||||
|
||||
"commands.diffViewUnified.label": "Use Unified Diff View",
|
||||
"commands.diffViewUnified.description": "Display tool-call diffs inline",
|
||||
"commands.diffViewUnified.keywords": "diff, unified, view",
|
||||
|
||||
"commands.toolOutputsDefault.label": "Tool Outputs Default · {state}",
|
||||
"commands.toolOutputsDefault.description": "Toggle default expansion for tool outputs",
|
||||
"commands.toolOutputsDefault.keywords": "tool, output, expand, collapse",
|
||||
|
||||
"commands.diagnosticsDefault.label": "Diagnostics Default · {state}",
|
||||
"commands.diagnosticsDefault.description": "Toggle default expansion for diagnostics output",
|
||||
"commands.diagnosticsDefault.keywords": "diagnostics, expand, collapse",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Token Usage Display · {state}",
|
||||
"commands.tokenUsageDisplay.description": "Show or hide token and cost stats for assistant messages",
|
||||
"commands.tokenUsageDisplay.keywords": "token, usage, cost, stats",
|
||||
|
||||
"commands.autoCleanupBlankSessions.label": "Auto-Cleanup Blank Sessions · {state}",
|
||||
"commands.autoCleanupBlankSessions.description": "Automatically clean up blank sessions when creating new ones",
|
||||
"commands.autoCleanupBlankSessions.keywords": "auto, cleanup, blank, sessions, toggle",
|
||||
|
||||
"commands.showHelp.label": "Show Help",
|
||||
"commands.showHelp.description": "Display keyboard shortcuts and help",
|
||||
"commands.showHelp.keywords": "shortcuts, help",
|
||||
|
||||
"commands.custom.argumentsPrompt.message": "Arguments for /{name}",
|
||||
"commands.custom.argumentsPrompt.title": "Custom command",
|
||||
"commands.custom.argumentsPrompt.inputLabel": "Arguments",
|
||||
"commands.custom.argumentsPrompt.inputPlaceholder": "e.g. foo bar",
|
||||
"commands.custom.argumentsPrompt.confirmLabel": "Run",
|
||||
"commands.custom.argumentsPrompt.cancelLabel": "Cancel",
|
||||
"commands.custom.argumentsPrompt.openFailed.message": "Failed to open arguments prompt.",
|
||||
"commands.custom.argumentsPrompt.openFailed.title": "Command arguments",
|
||||
"commands.custom.entries.descriptionFallback": "Custom command",
|
||||
"commands.custom.sessionRequired.message": "Select a session before running a custom command.",
|
||||
"commands.custom.sessionRequired.title": "Session required",
|
||||
"commands.custom.runFailed.message": "Failed to run custom command. Check the console for details.",
|
||||
"commands.custom.runFailed.title": "Command failed",
|
||||
|
||||
"unifiedPicker.loading.searching": "Searching...",
|
||||
"unifiedPicker.loading.loadingWorkspace": "Loading workspace...",
|
||||
"unifiedPicker.title.command": "Select Command",
|
||||
"unifiedPicker.title.mention": "Select Agent or File",
|
||||
"unifiedPicker.empty": "No results found",
|
||||
"unifiedPicker.sections.commands": "COMMANDS",
|
||||
"unifiedPicker.sections.agents": "AGENTS",
|
||||
"unifiedPicker.sections.files": "FILES",
|
||||
"unifiedPicker.badge.subagent": "subagent",
|
||||
"unifiedPicker.footer.navigate": "navigate",
|
||||
"unifiedPicker.footer.select": "select",
|
||||
"unifiedPicker.footer.close": "close",
|
||||
} as const
|
||||
16
packages/ui/src/lib/i18n/messages/en/dialogs.ts
Normal file
16
packages/ui/src/lib/i18n/messages/en/dialogs.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const dialogMessages = {
|
||||
"alertDialog.fallbackTitle.info": "Heads up",
|
||||
"alertDialog.fallbackTitle.warning": "Please review",
|
||||
"alertDialog.fallbackTitle.error": "Something went wrong",
|
||||
"alertDialog.actions.confirm": "Confirm",
|
||||
"alertDialog.actions.run": "Run",
|
||||
"alertDialog.actions.ok": "OK",
|
||||
"alertDialog.actions.cancel": "Cancel",
|
||||
"alertDialog.prompt.inputLabel": "Input",
|
||||
|
||||
"backgroundProcessOutputDialog.title": "Background Output",
|
||||
"backgroundProcessOutputDialog.actions.close": "Close",
|
||||
"backgroundProcessOutputDialog.loading": "Loading output...",
|
||||
"backgroundProcessOutputDialog.truncatedNotice": "Output truncated for display.",
|
||||
"backgroundProcessOutputDialog.loadErrorFallback": "Failed to load output.",
|
||||
} as const
|
||||
43
packages/ui/src/lib/i18n/messages/en/filesystem.ts
Normal file
43
packages/ui/src/lib/i18n/messages/en/filesystem.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export const filesystemMessages = {
|
||||
"directoryBrowser.defaultDescription": "Browse folders under the configured workspace root.",
|
||||
"directoryBrowser.close": "Close",
|
||||
"directoryBrowser.currentFolder": "Current folder",
|
||||
"directoryBrowser.selectCurrent": "Select Current",
|
||||
"directoryBrowser.newFolder": "New Folder",
|
||||
"directoryBrowser.creating": "Creating…",
|
||||
"directoryBrowser.loadingFolders": "Loading folders…",
|
||||
"directoryBrowser.noFolders": "No folders available.",
|
||||
"directoryBrowser.upOneLevel": "Up one level",
|
||||
"directoryBrowser.select": "Select",
|
||||
"directoryBrowser.load.errorFallback": "Unable to load filesystem",
|
||||
"directoryBrowser.createFolder.promptMessage": "Create a new folder in the current directory.",
|
||||
"directoryBrowser.createFolder.title": "New Folder",
|
||||
"directoryBrowser.createFolder.inputLabel": "Folder name",
|
||||
"directoryBrowser.createFolder.inputPlaceholder": "e.g. my-new-project",
|
||||
"directoryBrowser.createFolder.confirmLabel": "Create",
|
||||
"directoryBrowser.createFolder.cancelLabel": "Cancel",
|
||||
"directoryBrowser.createFolder.invalidNameMessage": "Please enter a single folder name.",
|
||||
"directoryBrowser.createFolder.invalidNameDetail": "Folder names cannot include slashes, '..', or '~'.",
|
||||
"directoryBrowser.createFolder.errorFallback": "Unable to create folder",
|
||||
|
||||
"filesystemBrowser.descriptionFallback": "Search for a path under the configured workspace root.",
|
||||
"filesystemBrowser.rootLabel": "Root: {root}",
|
||||
"filesystemBrowser.actions.close": "Close",
|
||||
"filesystemBrowser.actions.retry": "Retry",
|
||||
"filesystemBrowser.actions.select": "Select",
|
||||
"filesystemBrowser.filterLabel": "Filter",
|
||||
"filesystemBrowser.search.placeholder.directories": "Search for folders",
|
||||
"filesystemBrowser.search.placeholder.files": "Search for files",
|
||||
"filesystemBrowser.currentFolder.label": "Current folder",
|
||||
"filesystemBrowser.currentFolder.selectCurrent": "Select Current",
|
||||
"filesystemBrowser.loading.filesystem": "filesystem",
|
||||
"filesystemBrowser.loading.workspaceRoot": "workspace root",
|
||||
"filesystemBrowser.loading.loadingWithPath": "Loading {path}…",
|
||||
"filesystemBrowser.empty.noEntries": "No entries found.",
|
||||
"filesystemBrowser.navigation.upOneLevel": "Up one level",
|
||||
"filesystemBrowser.hints.navigate": "Navigate",
|
||||
"filesystemBrowser.hints.select": "Select",
|
||||
"filesystemBrowser.hints.close": "Close",
|
||||
"filesystemBrowser.errors.loadFilesystemFallback": "Unable to load filesystem",
|
||||
"filesystemBrowser.errors.openDirectoryFallback": "Unable to open directory",
|
||||
} as const
|
||||
@@ -1,4 +1,4 @@
|
||||
export const enMessages = {
|
||||
export const folderSelectionMessages = {
|
||||
"folderSelection.logoAlt": "CodeNomad logo",
|
||||
"folderSelection.tagline": "Select a folder to start coding with AI",
|
||||
|
||||
@@ -31,9 +31,4 @@ export const enMessages = {
|
||||
|
||||
"folderSelection.dialog.title": "Select Workspace",
|
||||
"folderSelection.dialog.description": "Select workspace to start coding.",
|
||||
|
||||
"time.relative.justNow": "just now",
|
||||
"time.relative.daysAgoShort": "{count}d ago",
|
||||
"time.relative.hoursAgoShort": "{count}h ago",
|
||||
"time.relative.minutesAgoShort": "{count}m ago",
|
||||
} as const
|
||||
36
packages/ui/src/lib/i18n/messages/en/index.ts
Normal file
36
packages/ui/src/lib/i18n/messages/en/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { advancedSettingsMessages } from "./advancedSettings"
|
||||
import { appMessages } from "./app"
|
||||
import { commandMessages } from "./commands"
|
||||
import { dialogMessages } from "./dialogs"
|
||||
import { filesystemMessages } from "./filesystem"
|
||||
import { folderSelectionMessages } from "./folderSelection"
|
||||
import { instanceMessages } from "./instance"
|
||||
import { loadingScreenMessages } from "./loadingScreen"
|
||||
import { logMessages } from "./logs"
|
||||
import { markdownMessages } from "./markdown"
|
||||
import { messagingMessages } from "./messaging"
|
||||
import { remoteAccessMessages } from "./remoteAccess"
|
||||
import { sessionMessages } from "./session"
|
||||
import { settingsMessages } from "./settings"
|
||||
import { timeMessages } from "./time"
|
||||
import { toolCallMessages } from "./toolCall"
|
||||
import { mergeMessageParts } from "./merge"
|
||||
|
||||
export const enMessages = mergeMessageParts(
|
||||
folderSelectionMessages,
|
||||
advancedSettingsMessages,
|
||||
loadingScreenMessages,
|
||||
timeMessages,
|
||||
appMessages,
|
||||
dialogMessages,
|
||||
filesystemMessages,
|
||||
instanceMessages,
|
||||
logMessages,
|
||||
sessionMessages,
|
||||
messagingMessages,
|
||||
toolCallMessages,
|
||||
markdownMessages,
|
||||
settingsMessages,
|
||||
remoteAccessMessages,
|
||||
commandMessages,
|
||||
)
|
||||
125
packages/ui/src/lib/i18n/messages/en/instance.ts
Normal file
125
packages/ui/src/lib/i18n/messages/en/instance.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
export const instanceMessages = {
|
||||
"instanceTabs.new.title": "New instance (Cmd/Ctrl+N)",
|
||||
"instanceTabs.new.ariaLabel": "New instance",
|
||||
"instanceTabs.remote.title": "Remote connect",
|
||||
"instanceTabs.remote.ariaLabel": "Remote connect",
|
||||
|
||||
"instanceInfo.title": "Instance Information",
|
||||
"instanceInfo.labels.folder": "Folder",
|
||||
"instanceInfo.labels.project": "Project",
|
||||
"instanceInfo.labels.versionControl": "Version Control",
|
||||
"instanceInfo.labels.opencodeVersion": "OpenCode Version",
|
||||
"instanceInfo.labels.binaryPath": "Binary Path",
|
||||
"instanceInfo.labels.environmentVariables": "Environment Variables ({count})",
|
||||
"instanceInfo.loading": "Loading...",
|
||||
"instanceInfo.server.title": "Server",
|
||||
"instanceInfo.server.port": "Port:",
|
||||
"instanceInfo.server.pid": "PID:",
|
||||
"instanceInfo.server.status": "Status:",
|
||||
|
||||
"instanceTab.status.permission": "Waiting on permission",
|
||||
"instanceTab.status.compacting": "Compacting",
|
||||
"instanceTab.status.working": "Working",
|
||||
"instanceTab.status.idle": "Idle",
|
||||
"instanceTab.status.ariaLabel": "Instance status: {status}",
|
||||
"instanceTab.actions.close.ariaLabel": "Close instance",
|
||||
|
||||
"instanceShell.leftPanel.sessionsTitle": "Sessions",
|
||||
"instanceShell.leftPanel.instanceInfo": "Instance Info",
|
||||
|
||||
"instanceShell.leftDrawer.pin": "Pin left drawer",
|
||||
"instanceShell.leftDrawer.unpin": "Unpin left drawer",
|
||||
"instanceShell.leftDrawer.toggle.pinned": "Left drawer pinned",
|
||||
"instanceShell.leftDrawer.toggle.open": "Open left drawer",
|
||||
"instanceShell.leftDrawer.toggle.close": "Close left drawer",
|
||||
|
||||
"instanceShell.rightDrawer.pin": "Pin right drawer",
|
||||
"instanceShell.rightDrawer.unpin": "Unpin right drawer",
|
||||
"instanceShell.rightDrawer.toggle.pinned": "Right drawer pinned",
|
||||
"instanceShell.rightDrawer.toggle.open": "Open right drawer",
|
||||
"instanceShell.rightDrawer.toggle.close": "Close right drawer",
|
||||
|
||||
"instanceShell.metrics.usedLabel": "Used",
|
||||
"instanceShell.metrics.availableLabel": "Avail",
|
||||
|
||||
"instanceShell.commandPalette.openAriaLabel": "Open command palette",
|
||||
"instanceShell.commandPalette.button": "Command Palette",
|
||||
|
||||
"instanceShell.connection.ariaLabel": "Connection {status}",
|
||||
"instanceShell.connection.connected": "Connected",
|
||||
"instanceShell.connection.connecting": "Connecting...",
|
||||
"instanceShell.connection.disconnected": "Disconnected",
|
||||
"instanceShell.connection.unknown": "Unknown",
|
||||
|
||||
"instanceWelcome.shortcuts.newSession": "New Session",
|
||||
"instanceWelcome.empty.title": "No Previous Sessions",
|
||||
"instanceWelcome.empty.description": "Create a new session below to get started",
|
||||
"instanceWelcome.loading.title": "Loading Sessions",
|
||||
"instanceWelcome.loading.description": "Fetching your previous sessions...",
|
||||
"instanceWelcome.resume.title": "Resume Session",
|
||||
"instanceWelcome.resume.subtitle.one": "{count} session available",
|
||||
"instanceWelcome.resume.subtitle.other": "{count} sessions available",
|
||||
"instanceWelcome.session.untitled": "Untitled Session",
|
||||
"instanceWelcome.new.title": "Start New Session",
|
||||
"instanceWelcome.new.subtitle": "We’ll reuse your last agent/model automatically",
|
||||
"instanceWelcome.new.createButton": "Create Session",
|
||||
"instanceWelcome.overlay.close": "Close",
|
||||
"instanceWelcome.actions.viewInstanceInfo": "View Instance Info",
|
||||
"instanceWelcome.actions.renameTitle": "Rename session",
|
||||
"instanceWelcome.actions.deleteTitle": "Delete session",
|
||||
"instanceWelcome.hints.navigate": "Navigate",
|
||||
"instanceWelcome.hints.jump": "Jump",
|
||||
"instanceWelcome.hints.firstLast": "First/Last",
|
||||
"instanceWelcome.hints.resume": "Resume",
|
||||
"instanceWelcome.hints.delete": "Delete",
|
||||
"instanceWelcome.toasts.renameError": "Unable to rename session",
|
||||
|
||||
"instanceDisconnected.title": "Instance Disconnected",
|
||||
"instanceDisconnected.folderFallback": "this workspace",
|
||||
"instanceDisconnected.reasonFallback": "The server stopped responding",
|
||||
"instanceDisconnected.description": "{folder} can no longer be reached. Close the tab to continue working.",
|
||||
"instanceDisconnected.details.title": "Details",
|
||||
"instanceDisconnected.details.folderLabel": "Folder:",
|
||||
"instanceDisconnected.actions.closeInstance": "Close Instance",
|
||||
|
||||
"instanceShell.empty.title": "No session selected",
|
||||
"instanceShell.empty.description": "Select a session to view messages",
|
||||
|
||||
"instanceShell.rightPanel.title": "Status Panel",
|
||||
"instanceShell.rightPanel.sections.plan": "Plan",
|
||||
"instanceShell.rightPanel.sections.backgroundProcesses": "Background Shells",
|
||||
"instanceShell.rightPanel.sections.mcp": "MCP Servers",
|
||||
"instanceShell.rightPanel.sections.lsp": "LSP Servers",
|
||||
"instanceShell.rightPanel.sections.plugins": "Plugins",
|
||||
|
||||
"instanceShell.plan.noSessionSelected": "Select a session to view plan.",
|
||||
"instanceShell.plan.empty": "Nothing planned yet.",
|
||||
|
||||
"instanceShell.backgroundProcesses.empty": "No background processes.",
|
||||
"instanceShell.backgroundProcesses.status": "Status: {status}",
|
||||
"instanceShell.backgroundProcesses.output": "Output: {sizeKb}KB",
|
||||
"instanceShell.backgroundProcesses.actions.output": "Output",
|
||||
"instanceShell.backgroundProcesses.actions.stop": "Stop",
|
||||
"instanceShell.backgroundProcesses.actions.terminate": "Terminate",
|
||||
|
||||
"versionPill.appWithVersion": "App {version}",
|
||||
"versionPill.ui": "UI",
|
||||
"versionPill.uiWithVersion": "UI {version}",
|
||||
"versionPill.source": " ({source})",
|
||||
|
||||
"opencodeBinarySelector.title": "OpenCode Binary",
|
||||
"opencodeBinarySelector.subtitle": "Choose which executable OpenCode should run",
|
||||
"opencodeBinarySelector.customPath.placeholder": "Enter path to opencode binary…",
|
||||
"opencodeBinarySelector.actions.add": "Add",
|
||||
"opencodeBinarySelector.actions.browse": "Browse for Binary…",
|
||||
"opencodeBinarySelector.actions.removeTitle": "Remove binary",
|
||||
"opencodeBinarySelector.badge.systemPath": "Use binary from system PATH",
|
||||
"opencodeBinarySelector.status.checkingVersions": "Checking versions…",
|
||||
"opencodeBinarySelector.status.checking": "Checking…",
|
||||
"opencodeBinarySelector.dialog.title": "Select OpenCode Binary",
|
||||
"opencodeBinarySelector.dialog.description": "Browse files exposed by the CLI server.",
|
||||
"opencodeBinarySelector.validation.invalidBinary": "Invalid OpenCode binary",
|
||||
"opencodeBinarySelector.validation.alreadyValidating": "Already validating",
|
||||
"opencodeBinarySelector.display.systemPath": "{name} (system PATH)",
|
||||
"opencodeBinarySelector.versionLabel": "v{version}",
|
||||
} as const
|
||||
17
packages/ui/src/lib/i18n/messages/en/loadingScreen.ts
Normal file
17
packages/ui/src/lib/i18n/messages/en/loadingScreen.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const loadingScreenMessages = {
|
||||
"loadingScreen.logoAlt": "CodeNomad logo",
|
||||
"loadingScreen.status.issue": "Encountered an issue",
|
||||
"loadingScreen.actions.showAnother": "Show another",
|
||||
"loadingScreen.errors.missingRoot": "Loading root element not found",
|
||||
|
||||
"loadingScreen.phrases.neurons": "Warming up the AI neurons…",
|
||||
"loadingScreen.phrases.daydreaming": "Convincing the AI to stop daydreaming…",
|
||||
"loadingScreen.phrases.goggles": "Polishing the AI’s code goggles…",
|
||||
"loadingScreen.phrases.reorganizingFiles": "Asking the AI to stop reorganizing your files…",
|
||||
"loadingScreen.phrases.coffee": "Feeding the AI additional coffee…",
|
||||
"loadingScreen.phrases.nodeModules": "Teaching the AI not to delete node_modules (again)…",
|
||||
"loadingScreen.phrases.actNatural": "Telling the AI to act natural before you arrive…",
|
||||
"loadingScreen.phrases.rewritingHistory": "Asking the AI to please stop rewriting history…",
|
||||
"loadingScreen.phrases.stretch": "Letting the AI stretch before its coding sprint…",
|
||||
"loadingScreen.phrases.keyboardControl": "Persuading the AI to give you keyboard control…",
|
||||
} as const
|
||||
18
packages/ui/src/lib/i18n/messages/en/logs.ts
Normal file
18
packages/ui/src/lib/i18n/messages/en/logs.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const logMessages = {
|
||||
"logsView.title": "Server Logs",
|
||||
"logsView.actions.show": "Show server logs",
|
||||
"logsView.actions.hide": "Hide server logs",
|
||||
"logsView.envVars.title": "Environment Variables ({count})",
|
||||
"logsView.paused.title": "Server logs are paused",
|
||||
"logsView.paused.description": "Enable streaming to watch your OpenCode server activity.",
|
||||
"logsView.empty.waiting": "Waiting for server output...",
|
||||
"logsView.scrollToBottom": "Scroll to bottom",
|
||||
|
||||
"infoView.logs.title": "Server Logs",
|
||||
"infoView.logs.actions.show": "Show server logs",
|
||||
"infoView.logs.actions.hide": "Hide server logs",
|
||||
"infoView.logs.paused.title": "Server logs are paused",
|
||||
"infoView.logs.paused.description": "Enable streaming to watch your OpenCode server activity.",
|
||||
"infoView.logs.empty.waiting": "Waiting for server output...",
|
||||
"infoView.logs.scrollToBottom": "Scroll to bottom",
|
||||
} as const
|
||||
7
packages/ui/src/lib/i18n/messages/en/markdown.ts
Normal file
7
packages/ui/src/lib/i18n/messages/en/markdown.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const markdownMessages = {
|
||||
"markdown.codeBlock.copy.label": "Copy",
|
||||
"markdown.codeBlock.copy.copied": "Copied!",
|
||||
"markdown.codeBlock.copy.failed": "Failed",
|
||||
|
||||
"markdown.copy": "Copy",
|
||||
} as const
|
||||
25
packages/ui/src/lib/i18n/messages/en/merge.ts
Normal file
25
packages/ui/src/lib/i18n/messages/en/merge.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export type MessageCatalog = Record<string, string>
|
||||
|
||||
type MergeParts<Parts extends readonly MessageCatalog[]> = Parts extends readonly [
|
||||
infer Head extends MessageCatalog,
|
||||
...infer Tail extends MessageCatalog[],
|
||||
]
|
||||
? Head & MergeParts<Tail>
|
||||
: {}
|
||||
|
||||
export function mergeMessageParts<const Parts extends readonly MessageCatalog[]>(
|
||||
...parts: Parts
|
||||
): MergeParts<Parts> {
|
||||
const result: Record<string, string> = Object.create(null)
|
||||
|
||||
for (const part of parts) {
|
||||
for (const [key, value] of Object.entries(part)) {
|
||||
if (key in result) {
|
||||
throw new Error(`Duplicate i18n message key: ${key}`)
|
||||
}
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return result as MergeParts<Parts>
|
||||
}
|
||||
109
packages/ui/src/lib/i18n/messages/en/messaging.ts
Normal file
109
packages/ui/src/lib/i18n/messages/en/messaging.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
export const messagingMessages = {
|
||||
"messageListHeader.sidebar.openSessionListAriaLabel": "Open session list",
|
||||
"messageListHeader.metrics.usedLabel": "Used",
|
||||
"messageListHeader.metrics.availableLabel": "Avail",
|
||||
"messageListHeader.commandPalette.ariaLabel": "Open command palette",
|
||||
"messageListHeader.commandPalette.button": "Command Palette",
|
||||
"messageListHeader.connection.connected": "Connected",
|
||||
"messageListHeader.connection.connecting": "Connecting...",
|
||||
"messageListHeader.connection.disconnected": "Disconnected",
|
||||
|
||||
"messageSection.empty.logoAlt": "CodeNomad logo",
|
||||
"messageSection.empty.brandTitle": "CodeNomad",
|
||||
"messageSection.empty.title": "Start a conversation",
|
||||
"messageSection.empty.description": "Type a message below or open the Command Palette:",
|
||||
"messageSection.empty.tips.commandPalette": "Command Palette",
|
||||
"messageSection.empty.tips.askAboutCodebase": "Ask about your codebase",
|
||||
"messageSection.empty.tips.attachFilesPrefix": "Attach files with",
|
||||
"messageSection.loading.messages": "Loading messages...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "Scroll to first message",
|
||||
"messageSection.scroll.toLatestAriaLabel": "Scroll to latest message",
|
||||
"messageSection.quote.addAsQuote": "Add as quote",
|
||||
"messageSection.quote.addAsCode": "Add as code",
|
||||
|
||||
"messageTimeline.ariaLabel": "Message timeline",
|
||||
"messageTimeline.segment.user.label": "You",
|
||||
"messageTimeline.segment.assistant.label": "Asst",
|
||||
"messageTimeline.segment.compaction.label": "Compaction",
|
||||
"messageTimeline.tool.fallbackLabel": "Tool Call",
|
||||
"messageTimeline.tooltip.userFallback": "User message",
|
||||
"messageTimeline.tooltip.assistantFallback": "Assistant response",
|
||||
"messageTimeline.tooltip.compaction.auto": "Auto Compaction",
|
||||
"messageTimeline.tooltip.compaction.manual": "User Compaction",
|
||||
"messageTimeline.text.filePrefix": "[File] {filename}",
|
||||
"messageTimeline.text.attachment": "Attachment",
|
||||
|
||||
"messageBlock.tool.header": "Tool Call",
|
||||
"messageBlock.tool.unknown": "unknown",
|
||||
"messageBlock.tool.goToSession.label": "Go to Session",
|
||||
"messageBlock.tool.goToSession.title": "Go to session",
|
||||
"messageBlock.tool.goToSession.unavailableTitle": "Session not available yet",
|
||||
|
||||
"messageBlock.compaction.ariaLabel": "Session compaction",
|
||||
"messageBlock.compaction.autoLabel": "Session auto-compacted",
|
||||
"messageBlock.compaction.manualLabel": "Session compacted by you",
|
||||
"messageBlock.usage.input": "Input",
|
||||
"messageBlock.usage.output": "Output",
|
||||
"messageBlock.usage.reasoning": "Reasoning",
|
||||
"messageBlock.usage.cacheRead": "Cache Read",
|
||||
"messageBlock.usage.cacheWrite": "Cache Write",
|
||||
"messageBlock.usage.cost": "Cost",
|
||||
"messageBlock.step.agentLabel": "Agent: {agent}",
|
||||
"messageBlock.step.modelLabel": "Model: {model}",
|
||||
"messageBlock.reasoning.thinkingLabel": "Thinking",
|
||||
"messageBlock.reasoning.expandAriaLabel": "Expand thinking",
|
||||
"messageBlock.reasoning.collapseAriaLabel": "Collapse thinking",
|
||||
"messageBlock.reasoning.indicator.hide": "Hide",
|
||||
"messageBlock.reasoning.indicator.view": "View",
|
||||
"messageBlock.reasoning.detailsAriaLabel": "Reasoning details",
|
||||
|
||||
"codeBlockInline.actions.copy": "Copy",
|
||||
"codeBlockInline.actions.copied": "Copied!",
|
||||
|
||||
"messageItem.speaker.you": "You",
|
||||
"messageItem.speaker.assistant": "Assistant",
|
||||
"messageItem.actions.revert": "Revert",
|
||||
"messageItem.actions.revertTitle": "Revert to this message",
|
||||
"messageItem.actions.fork": "Fork",
|
||||
"messageItem.actions.forkTitle": "Fork from this message",
|
||||
"messageItem.actions.copy": "Copy",
|
||||
"messageItem.actions.copyTitle": "Copy message",
|
||||
"messageItem.actions.copied": "Copied!",
|
||||
"messageItem.status.queued": "QUEUED",
|
||||
"messageItem.status.generating": "Generating...",
|
||||
"messageItem.status.sending": "Sending...",
|
||||
"messageItem.status.failedToSend": "Message failed to send",
|
||||
"messageItem.attachment.defaultName": "attachment",
|
||||
"messageItem.attachment.downloadAriaLabel": "Download {name}",
|
||||
"messageItem.agentMeta.agentLabel": "Agent: {agent}",
|
||||
"messageItem.agentMeta.modelLabel": "Model: {model}",
|
||||
"messageItem.errors.authenticationFallback": "Authentication error",
|
||||
"messageItem.errors.outputLengthExceeded": "Message output length exceeded",
|
||||
"messageItem.errors.requestAborted": "Request was aborted",
|
||||
"messageItem.errors.unknownFallback": "Unknown error occurred",
|
||||
|
||||
"attachmentChip.removeAriaLabel": "Remove attachment",
|
||||
|
||||
"expandButton.toggleAriaLabel": "Toggle chat input height",
|
||||
|
||||
"promptInput.placeholder.shell": "Run a shell command (Esc to exit)...",
|
||||
"promptInput.placeholder.default": "Type your message, @file, @agent, or paste images and text...",
|
||||
"promptInput.hints.shell.exit": "to exit shell mode",
|
||||
"promptInput.hints.shell.enable": "Shell mode",
|
||||
"promptInput.hints.commands": "Commands",
|
||||
"promptInput.history.previousAriaLabel": "Previous prompt",
|
||||
"promptInput.history.nextAriaLabel": "Next prompt",
|
||||
"promptInput.overlay.newLine": "New line",
|
||||
"promptInput.overlay.send": "Send",
|
||||
"promptInput.overlay.filesAgents": "Files/agents",
|
||||
"promptInput.overlay.history": "History",
|
||||
"promptInput.overlay.attachments": "• {count} file(s) attached",
|
||||
"promptInput.overlay.shellModeActive": "Shell mode active",
|
||||
"promptInput.overlay.press": "Press",
|
||||
"promptInput.overlay.againToAbort": "again to abort session",
|
||||
"promptInput.stopSession.ariaLabel": "Stop session",
|
||||
"promptInput.stopSession.title": "Stop session",
|
||||
"promptInput.send.ariaLabel": "Send message",
|
||||
"promptInput.send.errorFallback": "Failed to send message",
|
||||
"promptInput.send.errorTitle": "Send failed",
|
||||
} as const
|
||||
51
packages/ui/src/lib/i18n/messages/en/remoteAccess.ts
Normal file
51
packages/ui/src/lib/i18n/messages/en/remoteAccess.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
export const remoteAccessMessages = {
|
||||
"remoteAccess.eyebrow": "Remote handover",
|
||||
"remoteAccess.title": "Connect to CodeNomad remotely",
|
||||
"remoteAccess.subtitle": "Use the addresses below to open CodeNomad from another device.",
|
||||
"remoteAccess.close": "Close remote access",
|
||||
"remoteAccess.refresh": "Refresh",
|
||||
|
||||
"remoteAccess.sections.listeningMode.label": "Listening mode",
|
||||
"remoteAccess.sections.listeningMode.help": "Allow or limit remote handovers by binding to all interfaces or just localhost.",
|
||||
"remoteAccess.toggle.on": "On",
|
||||
"remoteAccess.toggle.off": "Off",
|
||||
"remoteAccess.toggle.title": "Allow connections from other IPs",
|
||||
"remoteAccess.toggle.caption.all": "Binding to 0.0.0.0",
|
||||
"remoteAccess.toggle.caption.local": "Binding to 127.0.0.1",
|
||||
"remoteAccess.toggle.note": "Changing this requires a restart and temporarily stops all active instances. Share the addresses below once the server restarts.",
|
||||
"remoteAccess.listeningMode.restartConfirm.message": "Restart to apply listening mode? This will stop all running instances.",
|
||||
"remoteAccess.listeningMode.restartConfirm.title.all": "Open to other devices",
|
||||
"remoteAccess.listeningMode.restartConfirm.title.local": "Limit to this device",
|
||||
"remoteAccess.listeningMode.restartConfirm.confirmLabel": "Restart now",
|
||||
"remoteAccess.listeningMode.restartConfirm.cancelLabel": "Cancel",
|
||||
"remoteAccess.restart.errorManual": "Unable to restart automatically. Please restart the app to apply the change.",
|
||||
|
||||
"remoteAccess.sections.serverPassword.label": "Server password",
|
||||
"remoteAccess.sections.serverPassword.help": "Remote handovers require a password. Set a memorable one to enable logins from other devices.",
|
||||
"remoteAccess.authStatus.unavailable": "Authentication status unavailable.",
|
||||
"remoteAccess.username": "Username: {username}",
|
||||
"remoteAccess.password.status.set": "A password is set for remote access.",
|
||||
"remoteAccess.password.status.unset": "No memorable password is set yet. Set one to allow remote handover logins.",
|
||||
"remoteAccess.password.actions.cancel": "Cancel",
|
||||
"remoteAccess.password.actions.change": "Change password",
|
||||
"remoteAccess.password.actions.set": "Set password",
|
||||
"remoteAccess.password.form.newPassword": "New password",
|
||||
"remoteAccess.password.form.confirmPassword": "Confirm password",
|
||||
"remoteAccess.password.form.placeholder": "At least 8 characters",
|
||||
"remoteAccess.password.error.tooShort": "Password must be at least 8 characters.",
|
||||
"remoteAccess.password.error.mismatch": "Passwords do not match.",
|
||||
"remoteAccess.password.save.saving": "Saving…",
|
||||
"remoteAccess.password.save.label": "Save password",
|
||||
|
||||
"remoteAccess.sections.addresses.label": "Reachable addresses",
|
||||
"remoteAccess.sections.addresses.help": "Launch or scan from another machine to hand over control.",
|
||||
"remoteAccess.addresses.loading": "Loading addresses…",
|
||||
"remoteAccess.addresses.none": "No addresses available yet.",
|
||||
"remoteAccess.address.scope.network": "Network",
|
||||
"remoteAccess.address.scope.loopback": "Loopback",
|
||||
"remoteAccess.address.scope.internal": "Internal",
|
||||
"remoteAccess.address.open": "Open",
|
||||
"remoteAccess.address.showQr": "Show QR",
|
||||
"remoteAccess.address.hideQr": "Hide QR",
|
||||
"remoteAccess.address.qrAlt": "QR for {url}",
|
||||
} as const
|
||||
67
packages/ui/src/lib/i18n/messages/en/session.ts
Normal file
67
packages/ui/src/lib/i18n/messages/en/session.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export const sessionMessages = {
|
||||
"sessionPicker.title": "OpenCode • {folder}",
|
||||
"sessionPicker.empty.noPrevious": "No previous sessions",
|
||||
"sessionPicker.resume.title": "Resume a session ({count}):",
|
||||
"sessionPicker.session.untitled": "Untitled",
|
||||
"sessionPicker.divider.or": "or",
|
||||
"sessionPicker.new.title": "Start new session:",
|
||||
"sessionPicker.agents.loading": "Loading agents...",
|
||||
"sessionPicker.actions.creating": "Creating...",
|
||||
"sessionPicker.actions.createSession": "Create Session",
|
||||
"sessionPicker.actions.cancel": "Cancel",
|
||||
|
||||
"sessionList.header.title": "Sessions",
|
||||
"sessionList.session.untitled": "Untitled",
|
||||
"sessionList.status.working": "Working",
|
||||
"sessionList.status.compacting": "Compacting",
|
||||
"sessionList.status.idle": "Idle",
|
||||
"sessionList.status.needsPermission": "Needs Permission",
|
||||
"sessionList.status.needsInput": "Needs Input",
|
||||
"sessionList.expand.collapseAriaLabel": "Collapse session",
|
||||
"sessionList.expand.expandAriaLabel": "Expand session",
|
||||
"sessionList.expand.collapseTitle": "Collapse",
|
||||
"sessionList.expand.expandTitle": "Expand",
|
||||
"sessionList.actions.copyId.ariaLabel": "Copy session ID",
|
||||
"sessionList.actions.copyId.title": "Copy session ID",
|
||||
"sessionList.actions.rename.ariaLabel": "Rename session",
|
||||
"sessionList.actions.rename.title": "Rename session",
|
||||
"sessionList.actions.delete.ariaLabel": "Delete session",
|
||||
"sessionList.actions.delete.title": "Delete session",
|
||||
"sessionList.copyId.success": "Session ID copied",
|
||||
"sessionList.copyId.error": "Unable to copy session ID",
|
||||
"sessionList.delete.error": "Unable to delete session",
|
||||
"sessionList.rename.error": "Unable to rename session",
|
||||
|
||||
"sessionRenameDialog.title": "Rename Session",
|
||||
"sessionRenameDialog.description.withLabel": "Update the title for \"{label}\".",
|
||||
"sessionRenameDialog.description.default": "Set a new title for this session.",
|
||||
"sessionRenameDialog.input.label": "Session name",
|
||||
"sessionRenameDialog.input.placeholder": "Enter a session name",
|
||||
"sessionRenameDialog.actions.cancel": "Cancel",
|
||||
"sessionRenameDialog.actions.rename": "Rename",
|
||||
"sessionRenameDialog.actions.renaming": "Renaming…",
|
||||
|
||||
"sessionView.fallback.sessionNotFound": "Session not found",
|
||||
"sessionView.alerts.abortFailed.message": "Failed to stop session",
|
||||
"sessionView.alerts.abortFailed.title": "Stop failed",
|
||||
"sessionView.alerts.revertFailed.message": "Failed to revert to message",
|
||||
"sessionView.alerts.revertFailed.title": "Revert failed",
|
||||
"sessionView.alerts.forkFailed.message": "Failed to fork session",
|
||||
"sessionView.alerts.forkFailed.title": "Fork failed",
|
||||
"sessionView.attachments.expandPastedTextAriaLabel": "Expand pasted text",
|
||||
"sessionView.attachments.insertPastedTextTitle": "Insert pasted text",
|
||||
"sessionView.attachments.removeAriaLabel": "Remove attachment",
|
||||
|
||||
"sessionEvents.sessionCompactedToast": "Session {label} was compacted",
|
||||
"sessionEvents.sessionError.unknown": "Unknown error",
|
||||
"sessionEvents.sessionError.title": "Session error",
|
||||
"sessionEvents.sessionError.message": "Error: {message}",
|
||||
|
||||
"sessionState.cleanup.deepConfirm.message": "This cleanup may be slow, and may delete sessions you didn't intend to delete. Are you sure?",
|
||||
"sessionState.cleanup.deepConfirm.title": "Deep Clean Sessions",
|
||||
"sessionState.cleanup.deepConfirm.detail": "Deep Clean Sessions will delete all sessions that have no messages, remove any finished sub-agent sessions, and clear out any unused forks of a session.",
|
||||
"sessionState.cleanup.deepConfirm.confirmLabel": "Continue",
|
||||
"sessionState.cleanup.deepConfirm.cancelLabel": "Cancel",
|
||||
"sessionState.cleanup.toast.one": "Cleaned up {count} blank session",
|
||||
"sessionState.cleanup.toast.other": "Cleaned up {count} blank sessions",
|
||||
} as const
|
||||
54
packages/ui/src/lib/i18n/messages/en/settings.ts
Normal file
54
packages/ui/src/lib/i18n/messages/en/settings.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export const settingsMessages = {
|
||||
"instanceServiceStatus.sections.lsp": "LSP Servers",
|
||||
"instanceServiceStatus.sections.mcp": "MCP Servers",
|
||||
"instanceServiceStatus.sections.plugins": "Plugins",
|
||||
"instanceServiceStatus.lsp.loading": "Loading LSP servers...",
|
||||
"instanceServiceStatus.lsp.empty": "No LSP servers detected.",
|
||||
"instanceServiceStatus.lsp.status.connected": "Connected",
|
||||
"instanceServiceStatus.lsp.status.error": "Error",
|
||||
"instanceServiceStatus.mcp.loading": "Loading MCP servers...",
|
||||
"instanceServiceStatus.mcp.empty": "No MCP servers detected.",
|
||||
"instanceServiceStatus.mcp.toggleAriaLabel": "Toggle {name} MCP server",
|
||||
"instanceServiceStatus.plugins.loading": "Loading plugins...",
|
||||
"instanceServiceStatus.plugins.empty": "No plugins configured.",
|
||||
|
||||
"permissionBanner.pendingRequests.one": "{count} pending request",
|
||||
"permissionBanner.pendingRequests.other": "{count} pending requests",
|
||||
"permissionBanner.detail.permission.one": "{count} permission",
|
||||
"permissionBanner.detail.permission.other": "{count} permissions",
|
||||
"permissionBanner.detail.question.one": "{count} question",
|
||||
"permissionBanner.detail.question.other": "{count} questions",
|
||||
"permissionBanner.detail.wrapper": " ({detail})",
|
||||
|
||||
"agentSelector.placeholder": "Select agent...",
|
||||
"agentSelector.badge.subagent": "subagent",
|
||||
"agentSelector.none": "None",
|
||||
"agentSelector.trigger.primary": "Agent: {agent}",
|
||||
|
||||
"modelSelector.placeholder.search": "Search models...",
|
||||
"modelSelector.none": "None",
|
||||
"modelSelector.trigger.primary": "Model: {model}",
|
||||
|
||||
"thinkingSelector.variant.default": "Default",
|
||||
"thinkingSelector.label": "Thinking: {variant}",
|
||||
|
||||
"envEditor.title": "Environment Variables",
|
||||
"envEditor.count.one": "({count} variable)",
|
||||
"envEditor.count.other": "({count} variables)",
|
||||
"envEditor.fields.name.placeholder": "Variable name",
|
||||
"envEditor.fields.name.readOnlyTitle": "Variable name (read-only)",
|
||||
"envEditor.fields.value.placeholder": "Variable value",
|
||||
"envEditor.actions.remove.title": "Remove variable",
|
||||
"envEditor.actions.add.title": "Add variable",
|
||||
"envEditor.empty": "No environment variables configured. Add variables above to customize the OpenCode environment.",
|
||||
"envEditor.help": "These variables will be available in the OpenCode environment when starting instances.",
|
||||
|
||||
"contextUsagePanel.headings.tokens": "Tokens",
|
||||
"contextUsagePanel.headings.context": "Context",
|
||||
"contextUsagePanel.labels.input": "Input",
|
||||
"contextUsagePanel.labels.output": "Output",
|
||||
"contextUsagePanel.labels.cost": "Cost",
|
||||
"contextUsagePanel.labels.used": "Used",
|
||||
"contextUsagePanel.labels.available": "Avail",
|
||||
"contextUsagePanel.unavailable": "--",
|
||||
} as const
|
||||
6
packages/ui/src/lib/i18n/messages/en/time.ts
Normal file
6
packages/ui/src/lib/i18n/messages/en/time.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const timeMessages = {
|
||||
"time.relative.justNow": "just now",
|
||||
"time.relative.daysAgoShort": "{count}d ago",
|
||||
"time.relative.hoursAgoShort": "{count}h ago",
|
||||
"time.relative.minutesAgoShort": "{count}m ago",
|
||||
} as const
|
||||
121
packages/ui/src/lib/i18n/messages/en/toolCall.ts
Normal file
121
packages/ui/src/lib/i18n/messages/en/toolCall.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
export const toolCallMessages = {
|
||||
"toolCall.pending.waitingToRun": "Waiting to run...",
|
||||
"toolCall.error.label": "Error:",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Diff view mode",
|
||||
"toolCall.diff.viewMode.split": "Split",
|
||||
"toolCall.diff.viewMode.unified": "Unified",
|
||||
|
||||
"toolCall.diagnostics.title": "Diagnostics",
|
||||
"toolCall.diagnostics.ariaLabel": "Diagnostics",
|
||||
"toolCall.diagnostics.ariaLabel.withLabel": "Diagnostics {label}",
|
||||
"toolCall.diagnostics.severity.error.short": "ERR",
|
||||
"toolCall.diagnostics.severity.warning.short": "WARN",
|
||||
"toolCall.diagnostics.severity.info.short": "INFO",
|
||||
|
||||
"toolCall.renderer.toolName.shell": "Shell",
|
||||
"toolCall.renderer.toolName.fetch": "Fetch",
|
||||
"toolCall.renderer.toolName.invalid": "Invalid",
|
||||
"toolCall.renderer.toolName.plan": "Plan",
|
||||
"toolCall.renderer.toolName.applyPatch": "Apply patch",
|
||||
|
||||
"toolCall.renderer.action.working": "Working...",
|
||||
"toolCall.renderer.action.writingCommand": "Writing command...",
|
||||
"toolCall.renderer.action.preparingEdit": "Preparing edit...",
|
||||
"toolCall.renderer.action.readingFile": "Reading file...",
|
||||
"toolCall.renderer.action.preparingWrite": "Preparing write...",
|
||||
"toolCall.renderer.action.preparingPatch": "Preparing patch...",
|
||||
"toolCall.renderer.action.planning": "Planning...",
|
||||
"toolCall.renderer.action.fetchingFromWeb": "Fetching from the web...",
|
||||
"toolCall.renderer.action.findingFiles": "Finding files...",
|
||||
"toolCall.renderer.action.searchingContent": "Searching content...",
|
||||
"toolCall.renderer.action.listingDirectory": "Listing directory...",
|
||||
|
||||
"toolCall.renderer.bash.title.timeout": "Timeout: {timeout}",
|
||||
"toolCall.renderer.read.detail.offset": "Offset: {offset}",
|
||||
"toolCall.renderer.read.detail.limit": "Limit: {limit}",
|
||||
|
||||
"toolCall.renderer.todo.empty": "No plan items yet.",
|
||||
"toolCall.renderer.todo.status.pending": "Pending",
|
||||
"toolCall.renderer.todo.status.inProgress": "In progress",
|
||||
"toolCall.renderer.todo.status.completed": "Completed",
|
||||
"toolCall.renderer.todo.status.cancelled": "Cancelled",
|
||||
"toolCall.renderer.todo.title.plan": "Plan",
|
||||
"toolCall.renderer.todo.title.creating": "Creating plan",
|
||||
"toolCall.renderer.todo.title.completing": "Completing plan",
|
||||
"toolCall.renderer.todo.title.updating": "Updating plan",
|
||||
|
||||
"toolCall.permission.status.required": "Permission Required",
|
||||
"toolCall.permission.status.queued": "Permission Queued",
|
||||
"toolCall.permission.requestedDiff.label": "Requested diff",
|
||||
"toolCall.permission.requestedDiff.withPath": "Requested diff · {path}",
|
||||
"toolCall.permission.queuedText": "Waiting for earlier permission responses.",
|
||||
"toolCall.permission.actions.allowOnce": "Allow Once",
|
||||
"toolCall.permission.actions.alwaysAllow": "Always Allow",
|
||||
"toolCall.permission.actions.deny": "Deny",
|
||||
"toolCall.permission.shortcuts.allowOnce": "Allow once",
|
||||
"toolCall.permission.shortcuts.alwaysAllow": "Always allow",
|
||||
"toolCall.permission.shortcuts.deny": "Deny",
|
||||
"toolCall.permission.errors.unableToUpdate": "Unable to update permission",
|
||||
|
||||
"permissionApproval.title": "Requests",
|
||||
"permissionApproval.empty": "No pending requests.",
|
||||
"permissionApproval.kind.permission": "Permission",
|
||||
"permissionApproval.kind.question": "Question",
|
||||
"permissionApproval.questionCount.one": "{count} question",
|
||||
"permissionApproval.questionCount.other": "{count} questions",
|
||||
"permissionApproval.status.active": "Active",
|
||||
"permissionApproval.actions.closeAriaLabel": "Close",
|
||||
"permissionApproval.actions.goToSession": "Go to Session",
|
||||
"permissionApproval.actions.loadingSession": "Loading…",
|
||||
"permissionApproval.actions.loadSession": "Load Session",
|
||||
"permissionApproval.actions.allowOnce": "Allow Once",
|
||||
"permissionApproval.actions.alwaysAllow": "Always Allow",
|
||||
"permissionApproval.actions.deny": "Deny",
|
||||
"permissionApproval.fallbackHint": "Load session for more information.",
|
||||
"permissionApproval.errors.unableToUpdatePermission": "Unable to update permission",
|
||||
|
||||
"toolCall.question.status.required": "Question Required",
|
||||
"toolCall.question.status.queued": "Question Queued",
|
||||
"toolCall.question.status.questions": "Questions",
|
||||
"toolCall.question.action.awaitingAnswers": "Awaiting answers...",
|
||||
"toolCall.question.title.questions": "Questions",
|
||||
"toolCall.question.title.askingQuestions": "Asking questions",
|
||||
"toolCall.question.type.one": "Question",
|
||||
"toolCall.question.type.other": "Questions",
|
||||
"toolCall.question.number": "Q{number}:",
|
||||
"toolCall.question.multiple": "Multiple",
|
||||
"toolCall.question.custom.title": "Type a custom answer",
|
||||
"toolCall.question.custom.label": "Custom answer",
|
||||
"toolCall.question.custom.placeholder": "Type your own answer",
|
||||
"toolCall.question.actions.submit": "Submit",
|
||||
"toolCall.question.actions.dismiss": "Dismiss",
|
||||
"toolCall.question.shortcuts.submit": "Submit",
|
||||
"toolCall.question.shortcuts.dismiss": "Dismiss",
|
||||
"toolCall.question.queuedText": "Waiting for earlier responses.",
|
||||
"toolCall.question.validation.answerAll": "Please answer all questions before submitting.",
|
||||
"toolCall.question.errors.unableToReply": "Unable to reply",
|
||||
"toolCall.question.errors.unableToDismiss": "Unable to dismiss",
|
||||
|
||||
"toolCall.task.action.delegating": "Delegating...",
|
||||
"toolCall.task.sections.prompt": "Prompt",
|
||||
"toolCall.task.sections.steps": "Steps",
|
||||
"toolCall.task.sections.output": "Output",
|
||||
"toolCall.task.steps.count": "{count} steps",
|
||||
"toolCall.task.meta.agentModel": "Agent: {agent} • Model: {model}",
|
||||
"toolCall.task.meta.agent": "Agent: {agent}",
|
||||
"toolCall.task.meta.model": "Model: {model}",
|
||||
|
||||
"toolCall.status.pending": "Pending",
|
||||
"toolCall.status.running": "Running",
|
||||
"toolCall.status.completed": "Completed",
|
||||
"toolCall.status.error": "Error",
|
||||
"toolCall.status.unknown": "Unknown",
|
||||
|
||||
"toolCall.applyPatch.action.preparing": "Preparing apply_patch...",
|
||||
"toolCall.applyPatch.title.withFileCount.one": "{tool} ({count} file)",
|
||||
"toolCall.applyPatch.title.withFileCount.other": "{tool} ({count} files)",
|
||||
"toolCall.applyPatch.fileFallback": "File {number}",
|
||||
} as const
|
||||
Reference in New Issue
Block a user