feat: multi-language interface (zh-CN/zh-TW/en/ja), multilingual offline changelog, settings robustness
i18n - shared/i18n: dependency-free t() with flat per-namespace dictionaries (common/settings/workspace/terminal/ssh/panels/main), zh-CN fallback - language picker in Settings -> System; antd ConfigProvider locale follows it - main process tracks the language too: tray menu, close prompt, ssh/sftp/ zmodem errors and the log TUI marker are translated; tray rebuilds on change changelog - CHANGELOG.md (zh-CN canonical) + .zh-TW/.en/.ja, bundled via ?raw and read per interface language with per-version fallback to zh-CN (no network) - sync-changelog.cjs merges RELEASE_NOTES[.<lang>].md per release; release.cjs refuses to publish without a zh-CN entry for the version settings robustness - closeAction 'ask' survives the sanitizer (was silently coerced to 'tray', which made the 'ask every time' option dead) - highlight rules are repaired instead of dropped: string priority, 0/1 enabled, missing fg colour; unknown fields preserved - load-time warnings are written to settings-warnings.log (deduped, capped) terminal/UI - configurable terminal toolbar: open working directory (default on), session log recording (off), open logs folder (off) - global shortcut field records key combos (modifier or F-key required) - input suggestions + command history default to off, with a one-time reset migration for existing installs - settings dialog scrolling fixed (antd v6 renamed the tabs container), theme gallery nested scrollbar removed, joined segmented pickers with readable selected-state text tests: settings-store.mjs (15 checks) added; commands-store.mjs updated for the new off-by-default history setting
This commit is contained in:
1 parent
34094d607b
commit
4c6a29ef28
82 files changed
+3342
-608
No files matched your search
@@ -0,0 +1,17 @@
|
||||
/** Namespace: common (i18n plumbing, generic buttons/status). Owner: i18n infrastructure. */
|
||||
const common: Record<string, string> = {
|
||||
'common.ok': 'OK',
|
||||
'common.cancel': 'Cancel',
|
||||
'common.close': 'Close',
|
||||
'common.save': 'Save',
|
||||
'common.delete': 'Delete',
|
||||
'common.edit': 'Edit',
|
||||
'common.add': 'Add',
|
||||
'common.copy': 'Copy',
|
||||
'common.paste': 'Paste',
|
||||
'common.reset': 'Reset to defaults',
|
||||
'common.language': 'Language',
|
||||
'common.languageDesc': 'Switches the interface language immediately; saved permanently.'
|
||||
}
|
||||
|
||||
export default common
|
||||
@@ -0,0 +1,19 @@
|
||||
import common from './common'
|
||||
import settings from './settings'
|
||||
import workspace from './workspace'
|
||||
import terminal from './terminal'
|
||||
import ssh from './ssh'
|
||||
import panels from './panels'
|
||||
import main from './main'
|
||||
|
||||
/** English entries. Namespace files are owned per area — see the ownership map
|
||||
* in src/shared/i18n/index.ts. */
|
||||
export default {
|
||||
...common,
|
||||
...settings,
|
||||
...workspace,
|
||||
...terminal,
|
||||
...ssh,
|
||||
...panels,
|
||||
...main
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/** Namespace: main (main-process strings: tray, close prompt, updater). Owner: main process. */
|
||||
const main: Record<string, string> = {
|
||||
'main.tray.showWindow': 'Show main window',
|
||||
'main.tray.closeAction': 'Close button action',
|
||||
'main.tray.askEveryTime': 'Ask every time',
|
||||
'main.tray.minimizeToTray': 'Minimize to tray',
|
||||
'main.tray.exitDirectly': 'Exit directly',
|
||||
'main.tray.exit': 'Exit',
|
||||
'main.tray.balloonTitle': 'Minimized to tray',
|
||||
'main.tray.balloonContent': 'Terminal sessions keep running in the background. Click the tray icon to restore the window.',
|
||||
'main.tray.closeTitle': 'Close OpenTerminal',
|
||||
'main.tray.closeMessage': 'Minimize to tray, or exit now?',
|
||||
'main.tray.closeDetail': 'Minimizing to tray keeps your terminal sessions running.',
|
||||
'main.tray.rememberChoice': 'Remember my choice, never ask again',
|
||||
|
||||
'main.updater.feedFailed': 'Domestic feed: {gitea}; GitHub: {github}',
|
||||
|
||||
'main.ssh.connectTimeout': 'Connection timed out ({host}:{port})',
|
||||
'main.ssh.saveFingerprintFailed': 'Failed to save the host fingerprint: {detail}',
|
||||
'main.ssh.hostKeyRejected': 'The user rejected the host key',
|
||||
'main.ssh.connectFailed': 'Connection failed {host}:{port}: {detail}',
|
||||
'main.ssh.shellOpenFailed': 'Could not open the SSH shell ({host}:{port}): {detail}',
|
||||
'main.ssh.initFailed': 'SSH connection initialization failed ({host}:{port}): {detail}',
|
||||
'main.ssh.readKeyFailed': 'Could not read the private key file {path}: {detail}',
|
||||
|
||||
'main.sftp.sessionGone': 'The SSH session does not exist or has disconnected',
|
||||
'main.sftp.deleteFailed': 'Delete failed: {detail}',
|
||||
'main.sftp.invalidMode': 'Invalid permission value: {mode}',
|
||||
'main.sftp.invalidUidGid': 'Invalid uid/gid',
|
||||
'main.sftp.commandExitCode': 'Command exited with code {code}',
|
||||
'main.sftp.cancelled': 'Cancelled',
|
||||
|
||||
'main.zmodem.transferFailed': 'Transfer failed',
|
||||
'main.zmodem.transferTimeout': 'Transfer timed out',
|
||||
'main.zmodem.sendFailed': 'Sending failed',
|
||||
'main.zmodem.uploadFailed': 'Upload failed',
|
||||
'main.zmodem.receiveFailed': 'Receiving failed',
|
||||
'main.zmodem.abnormal': 'ZMODEM transfer error',
|
||||
'main.zmodem.cancelled': 'Cancelled',
|
||||
'main.zmodem.offerTimedOut': 'No files selected, cancelled',
|
||||
'main.zmodem.sessionInvalid': 'The session is no longer valid',
|
||||
'main.zmodem.sessionCreateFailed': 'Could not establish the ZMODEM session',
|
||||
'main.zmodem.noSaveDir': 'No save directory specified',
|
||||
'main.zmodem.noFiles': 'No files selected',
|
||||
|
||||
'main.ipc.connectionMissing': 'Connection bookmark not found ({id})',
|
||||
|
||||
'main.sysinfo.sessionGone': 'SSH session is missing or disconnected',
|
||||
'main.sysinfo.execFailed': 'SSH exec failed',
|
||||
'main.sysinfo.parseFailed': 'Parse failed: {message}',
|
||||
'main.pty.serviceNotReady': 'SSH session service is not initialised yet',
|
||||
'main.pty.missingConnectionId': 'SSH session is missing its connectionId',
|
||||
'main.log.tuiOmitted': 'full-screen (TUI) output omitted'
|
||||
}
|
||||
|
||||
export default main
|
||||
@@ -0,0 +1,36 @@
|
||||
/** Namespace: panels (command panel, session-log panel, transfer panel). Owner: panels area. */
|
||||
const panels: Record<string, string> = {
|
||||
// Command panel
|
||||
'panels.commands.sectionTitle': 'Commands',
|
||||
'panels.commands.target': 'Send to',
|
||||
'panels.commands.targetSsh': 'SSH server',
|
||||
'panels.commands.targetTerminal': 'Terminal',
|
||||
'panels.commands.tabHistory': 'History',
|
||||
'panels.commands.tabLibrary': 'Library',
|
||||
'panels.commands.historyTitle': 'Command history',
|
||||
'panels.commands.clearTitle': 'Clear all command history?',
|
||||
'panels.commands.clear': 'Clear',
|
||||
'panels.commands.noHistory': 'No command history',
|
||||
'panels.commands.loading': 'Loading…',
|
||||
'panels.commands.libraryTitle': 'Command library',
|
||||
'panels.commands.libraryEmpty': 'The command library is empty',
|
||||
'panels.commands.add': 'Add command',
|
||||
'panels.commands.name': 'Name',
|
||||
'panels.commands.optional': '(optional)',
|
||||
'panels.commands.command': 'Command',
|
||||
'panels.commands.commandPlaceholder': 'e.g. ls -la',
|
||||
'panels.commands.note': 'Note',
|
||||
'panels.commands.deleteTitle': 'Delete this command?',
|
||||
'panels.commands.deleteAria': 'Delete command',
|
||||
|
||||
// Transfer panel
|
||||
'panels.transfer.failed': 'Transfer failed',
|
||||
'panels.transfer.cancelled': 'Cancelled',
|
||||
'panels.transfer.done': 'Transfer complete',
|
||||
'panels.transfer.uploading': 'Uploading',
|
||||
'panels.transfer.downloading': 'Downloading',
|
||||
'panels.transfer.zmodemUploading': 'ZMODEM uploading',
|
||||
'panels.transfer.zmodemDownloading': 'ZMODEM downloading'
|
||||
}
|
||||
|
||||
export default panels
|
||||
@@ -0,0 +1,153 @@
|
||||
/** Namespace: settings (the settings dialog: font/cursor/render/highlight/theme/system/about). Owner: settings page. */
|
||||
const settings: Record<string, string> = {
|
||||
'settings.title': 'Settings',
|
||||
'settings.tabs.font': 'Font',
|
||||
'settings.tabs.cursor': 'Cursor & Scrollback',
|
||||
'settings.tabs.render': 'Rendering & Behavior',
|
||||
'settings.tabs.highlight': 'Highlighting',
|
||||
'settings.tabs.theme': 'Themes',
|
||||
'settings.tabs.system': 'System',
|
||||
'settings.tabs.about': 'About',
|
||||
'settings.resizeHandle': 'Drag to resize',
|
||||
'settings.preview': 'Preview',
|
||||
'settings.deleteConfirmDesc': 'This cannot be undone. Continue?',
|
||||
'settings.color.foreground': 'Foreground',
|
||||
'settings.color.background': 'Background',
|
||||
'settings.color.cursor': 'Cursor',
|
||||
'settings.color.selection': 'Selection',
|
||||
'settings.font.label': 'Font',
|
||||
'settings.font.desc': 'The built-in default or a system monospace font',
|
||||
'settings.font.placeholder': 'Select a font',
|
||||
'settings.font.default': 'Default',
|
||||
'settings.font.size': 'Font size',
|
||||
'settings.font.sizeDesc': 'Pixel size of the terminal text',
|
||||
'settings.font.weight': 'Weight',
|
||||
'settings.font.weightDesc': '400 is regular, 700 is bold',
|
||||
'settings.font.boldWeight': 'Bold weight',
|
||||
'settings.font.boldWeightDesc': 'Weight used for bold text',
|
||||
'settings.font.letterSpacing': 'Letter spacing',
|
||||
'settings.font.letterSpacingDesc': 'Horizontal distance between characters',
|
||||
'settings.font.lineHeight': 'Line height',
|
||||
'settings.font.lineHeightDesc': 'Vertical distance between adjacent lines',
|
||||
'settings.cursor.blink': 'Blinking cursor',
|
||||
'settings.cursor.blinkDesc': 'Whether the cursor blinks periodically',
|
||||
'settings.cursor.style': 'Cursor style',
|
||||
'settings.cursor.styleDesc': 'Shape used to draw the cursor',
|
||||
'settings.cursor.inactiveStyle': 'Inactive cursor style',
|
||||
'settings.cursor.inactiveStyleDesc': 'Cursor style while the window is unfocused',
|
||||
'settings.cursor.scrollback': 'Scrollback buffer',
|
||||
'settings.cursor.scrollbackDesc': 'How many lines you can scroll back',
|
||||
'settings.cursorStyle.bar': 'Bar',
|
||||
'settings.cursorStyle.block': 'Block',
|
||||
'settings.cursorStyle.underline': 'Underline',
|
||||
'settings.cursorStyle.outline': 'Outline',
|
||||
'settings.cursorStyle.none': 'None',
|
||||
'settings.rendererMode.auto': 'Automatic',
|
||||
'settings.rendererMode.autoHint': 'Prefer WebGL acceleration, falling back to DOM rendering if it fails',
|
||||
'settings.rendererMode.webgl': 'High-performance WebGL',
|
||||
'settings.rendererMode.webglHint':
|
||||
'Force GPU-accelerated rendering; best for high refresh rates and heavy scrolling',
|
||||
'settings.rendererMode.dom': 'Compatible DOM',
|
||||
'settings.rendererMode.domHint':
|
||||
'Pure CPU rendering with the widest compatibility; best without a GPU or over remote desktop',
|
||||
'settings.render.modeLabel': 'Renderer',
|
||||
'settings.render.modeHint': 'How terminal cells are accelerated; applies to every terminal',
|
||||
'settings.render.autoWrap': 'Auto wrap',
|
||||
'settings.render.autoWrapDesc': 'Wrap lines that exceed the width',
|
||||
'settings.render.copyOnSelect': 'Copy on select',
|
||||
'settings.render.copyOnSelectDesc': 'Copy text automatically when you select it with the mouse',
|
||||
'settings.render.pasteRiskConfirm': 'Confirm risky paste',
|
||||
'settings.render.pasteRiskConfirmDesc':
|
||||
'Ask before pasting multi-line text (or a very long single line); single lines paste directly',
|
||||
'settings.render.suggest': 'Input suggestions',
|
||||
'settings.render.suggestDesc':
|
||||
'Show command suggestions while typing; Tab accepts, Enter always runs the command right away',
|
||||
'settings.render.history': 'Record command history',
|
||||
'settings.render.historyDesc': 'When off, new commands are no longer recorded; saved history is kept',
|
||||
'settings.render.historyLimit': 'History limit',
|
||||
'settings.render.historyLimitDesc': 'Most commands to keep; duplicates are stored only once',
|
||||
'settings.render.recButton': 'Terminal toolbar · Record',
|
||||
'settings.render.recButtonDesc': 'Show the "Record session log" button in the top-right corner',
|
||||
'settings.render.openLogsButton': 'Terminal toolbar · Open log folder',
|
||||
'settings.render.openLogsButtonDesc': 'Show the "Open log folder" button in the top-right corner',
|
||||
'settings.render.openCwdButton': 'Terminal toolbar · Open workspace folder',
|
||||
'settings.render.openCwdButtonDesc':
|
||||
'Show the "Open current folder" button in the top-right corner (hidden in SSH sessions; the folder follows cd in real time and needs shell integration or the cd command)',
|
||||
'settings.system.launchAtLogin': 'Launch at startup',
|
||||
'settings.system.launchAtLoginDesc':
|
||||
'Start OpenTerminal when the system boots (in development mode the dev build is registered)',
|
||||
'settings.system.preventSleep': 'Prevent system sleep',
|
||||
'settings.system.preventSleepDesc':
|
||||
'While on, OpenTerminal keeps the system from sleeping automatically; when off, the system follows its own power settings',
|
||||
'settings.system.restoreSession': 'Restore last session on startup',
|
||||
'settings.system.restoreSessionDesc':
|
||||
'Restore the split layout on the next launch and return each terminal to its last directory; when off, OpenTerminal always starts with a single terminal',
|
||||
'settings.system.shellIntegration': 'Shell integration',
|
||||
'settings.system.shellIntegrationDesc':
|
||||
'Let the shell report its working directory (OSC 7) for more precise path tracking, including cd inside scripts; it wraps your prompt, so turn it off if the prompt theme looks wrong',
|
||||
'settings.system.closeAction': 'Close button behavior',
|
||||
'settings.system.closeActionDesc':
|
||||
'What happens when you click the window close button; after minimizing to the tray you can quit from the tray icon context menu',
|
||||
'settings.system.closeActionTray': 'Minimize to tray',
|
||||
'settings.system.closeActionExit': 'Quit directly',
|
||||
'settings.system.closeActionAsk': 'Ask every time',
|
||||
'settings.system.globalShortcut': 'Global show/hide shortcut',
|
||||
'settings.system.globalShortcutDesc':
|
||||
'Click the field, then press the key combination; Esc cancels, Backspace clears and disables it',
|
||||
'settings.system.globalShortcutHint':
|
||||
'Together with the global key this shows or hides the window from anywhere; if registration fails (a conflict with another app) it simply has no effect and the app reports no error.',
|
||||
'settings.system.shortcutRecording': 'Press the keys…',
|
||||
'settings.system.shortcutPlaceholder': 'Click and press a shortcut, leave empty to disable',
|
||||
'settings.highlight.alert':
|
||||
'Custom highlighting improves readability at a small performance cost. Rules are applied in priority order. PS: colors are injected as text is written to the terminal, so existing scrollback is unaffected',
|
||||
'settings.highlight.enabled': 'Enabled',
|
||||
'settings.highlight.pattern': 'Pattern',
|
||||
'settings.highlight.patternPlaceholder': 'e.g. \\b(ERROR|FAILED)\\b',
|
||||
'settings.highlight.invalidRegex': 'Invalid regular expression',
|
||||
'settings.highlight.priority': 'Priority',
|
||||
'settings.highlight.priorityHint': 'Lower values apply first',
|
||||
'settings.highlight.color': 'Color',
|
||||
'settings.highlight.clearBg': 'Clear',
|
||||
'settings.highlight.addBg': 'Add',
|
||||
'settings.highlight.palette': 'Palette',
|
||||
'settings.highlight.note': 'Note',
|
||||
'settings.highlight.notePlaceholder': 'Rule description (optional)',
|
||||
'settings.highlight.actions': 'Actions',
|
||||
'settings.highlight.addRule': '+ Add rule',
|
||||
'settings.highlight.empty': 'No highlight rules yet — click "+ Add rule" to create one',
|
||||
'settings.highlight.deleteTitle': 'Delete highlight rule',
|
||||
'settings.highlight.resetTitle': 'Restore default highlight rules',
|
||||
'settings.highlight.resetDesc': 'Replaces every current rule with the built-in presets. This cannot be undone.',
|
||||
'settings.highlight.resetOk': 'Restore',
|
||||
'settings.highlight.createTitle': 'New highlight rule',
|
||||
'settings.highlight.editTitle': 'Edit highlight rule',
|
||||
'settings.theme.accent': 'Tab accent color',
|
||||
'settings.theme.accentDesc': 'Accent color for the active tab border, the sidebar indicator, and SSH badges',
|
||||
'settings.theme.customBadge': 'Custom',
|
||||
'settings.theme.deleteTitle': 'Delete custom theme',
|
||||
'settings.theme.create': 'New theme',
|
||||
'settings.theme.editTitle': 'Edit theme',
|
||||
'settings.themeEditor.name': 'Name',
|
||||
'settings.themeEditor.namePlaceholder': 'Theme name',
|
||||
'settings.themeEditor.copySuffix': ' (copy)',
|
||||
'settings.about.currentVersion': 'Current version',
|
||||
'settings.about.statusIdle': 'Click to check for updates',
|
||||
'settings.about.statusChecking': 'Checking for updates…',
|
||||
'settings.about.statusAvailable': 'A new version is available',
|
||||
'settings.about.statusLatest': 'Already up to date',
|
||||
'settings.about.statusDownloading': 'Downloading…',
|
||||
'settings.about.statusDownloaded': 'Download complete — restart to install',
|
||||
'settings.about.statusError': 'Check failed',
|
||||
'settings.about.statusDev': 'Update checks are unavailable in development mode',
|
||||
'settings.about.channelStable': 'Stable channel',
|
||||
'settings.about.autoCheck': 'Check automatically at startup',
|
||||
'settings.about.download': 'Download update',
|
||||
'settings.about.downloadGithub': ' (GitHub source)',
|
||||
'settings.about.install': 'Restart and install',
|
||||
'settings.about.check': 'Check for updates',
|
||||
'settings.about.checkingButton': 'Checking',
|
||||
'settings.about.changelog': 'Changelog',
|
||||
'settings.about.changelogEmpty': 'No changelog available'
|
||||
}
|
||||
|
||||
export default settings
|
||||
@@ -0,0 +1,150 @@
|
||||
/** Namespace: ssh (ssh connections, host key prompt, file panel, zmodem, monitor). Owner: ssh area. */
|
||||
const ssh: Record<string, string> = {
|
||||
// Auth method / secret kind
|
||||
'ssh.auth.password': 'Password',
|
||||
'ssh.auth.privateKey': 'Private key',
|
||||
'ssh.auth.agent': 'Agent',
|
||||
'ssh.secret.passphrase': 'Passphrase',
|
||||
|
||||
// Connection dialog: auth fields
|
||||
'ssh.fields.agentDesc':
|
||||
'Authenticate with a key already loaded in the local SSH Agent; this app stores nothing for you.',
|
||||
'ssh.fields.askPasswordLabel': 'Ask for password on connect',
|
||||
'ssh.fields.askPasswordHint':
|
||||
'Prompts for the password on every connection instead of using the saved one',
|
||||
'ssh.fields.passwordPlaceholder': 'Leave empty to keep the saved password',
|
||||
'ssh.fields.keyPath': 'Private key path (path on the server, optional)',
|
||||
'ssh.fields.keyContent': 'Private key content',
|
||||
'ssh.fields.keyContentPlaceholder':
|
||||
'Paste the private key; leave empty to use the path above (leave empty while editing to keep the saved key)',
|
||||
'ssh.fields.askPassphraseLabel': 'Ask for passphrase on connect',
|
||||
'ssh.fields.askPassphraseHint': 'Prompts for the key passphrase on every connection',
|
||||
'ssh.fields.passphrase': 'Key passphrase',
|
||||
'ssh.fields.passphrasePlaceholder': 'Leave empty to keep the saved passphrase',
|
||||
|
||||
// Connection dialog
|
||||
'ssh.dialog.titleEdit': 'Edit connection',
|
||||
'ssh.dialog.titleNew': 'New connection',
|
||||
'ssh.dialog.saveFailed': 'Save failed. Check your input and try again.',
|
||||
'ssh.dialog.name': 'Name',
|
||||
'ssh.dialog.nameRequired': 'Please enter a connection name',
|
||||
'ssh.dialog.namePlaceholder': 'e.g. Production server',
|
||||
'ssh.dialog.group': 'Group',
|
||||
'ssh.dialog.groupPlaceholder': 'Pick or type a new group; leave empty for “Default”',
|
||||
'ssh.dialog.host': 'Host',
|
||||
'ssh.dialog.hostRequired': 'Please enter a host address',
|
||||
'ssh.dialog.hostPlaceholder': '192.168.1.10 or example.com',
|
||||
'ssh.dialog.port': 'Port',
|
||||
'ssh.dialog.portRange': 'Port must be between 1 and 65535',
|
||||
'ssh.dialog.username': 'Username',
|
||||
'ssh.dialog.usernameRequired': 'Please enter a username',
|
||||
'ssh.dialog.authMethod': 'Authentication',
|
||||
'ssh.dialog.savedSecret': 'A {kind} is saved; leave empty to keep it',
|
||||
'ssh.dialog.keepalive': 'Keepalive interval (seconds)',
|
||||
'ssh.dialog.keepaliveTooltip': '0 disables keepalive',
|
||||
'ssh.dialog.keepaliveMin': 'Cannot be negative',
|
||||
|
||||
// Connection sidebar
|
||||
'ssh.sidebar.defaultGroup': 'Default',
|
||||
'ssh.sidebar.timeJustNow': 'just now',
|
||||
'ssh.sidebar.timeMinutesAgo': '{n} min ago',
|
||||
'ssh.sidebar.timeHoursAgo': '{n} h ago',
|
||||
'ssh.sidebar.timeDaysAgo': '{n} d ago',
|
||||
'ssh.sidebar.modeTerminal': 'Terminal workspace',
|
||||
'ssh.sidebar.modeSsh': 'SSH workspace',
|
||||
'ssh.sidebar.title': 'Connections',
|
||||
'ssh.sidebar.newConnection': 'New connection',
|
||||
'ssh.sidebar.sectionTerminals': 'Terminals',
|
||||
'ssh.sidebar.noLocalTerminals': 'No local terminal open',
|
||||
'ssh.sidebar.local': 'Local',
|
||||
'ssh.sidebar.sectionServers': 'SSH servers',
|
||||
'ssh.sidebar.empty': 'No connections yet — click + to create one',
|
||||
'ssh.sidebar.loading': 'Loading…',
|
||||
'ssh.sidebar.recent': 'Recent sessions',
|
||||
'ssh.sidebar.dblClickConnect': 'Double-click to connect to {host}',
|
||||
'ssh.sidebar.deleteTitle': 'Delete this connection?',
|
||||
'ssh.sidebar.deleteDesc':
|
||||
'A deleted connection cannot be restored. Its saved key material is removed as well.',
|
||||
|
||||
// Host key verification
|
||||
'ssh.hostKey.changedTitle': 'Host fingerprint changed!',
|
||||
'ssh.hostKey.unknownHost': 'Unknown host',
|
||||
'ssh.hostKey.accept': 'Accept and connect',
|
||||
'ssh.hostKey.reject': 'Reject',
|
||||
'ssh.hostKey.mitmTitle': 'Possible man-in-the-middle attack',
|
||||
'ssh.hostKey.mitmDesc':
|
||||
'The remote host key fingerprint differs from the one recorded earlier. Unless you changed the server key yourself, someone may be impersonating this host.',
|
||||
'ssh.hostKey.firstConnect':
|
||||
'First connection to this host; its fingerprint has not been recorded yet.',
|
||||
'ssh.hostKey.target': 'Host: {target}',
|
||||
'ssh.hostKey.fingerprint': 'Fingerprint: {fingerprint}',
|
||||
|
||||
// SSH workspace: file panel container, host badge
|
||||
'ssh.bottomPanel.resize': 'Resize the file panel',
|
||||
'ssh.hostBadge.aria': 'SSH host {label}',
|
||||
|
||||
// ZMODEM
|
||||
'ssh.zmodem.done': 'ZMODEM transfer complete',
|
||||
'ssh.zmodem.failed': 'ZMODEM transfer failed: {message}',
|
||||
'ssh.zmodem.unknownError': 'unknown error',
|
||||
'ssh.zmodem.titleReceive': 'Download to local',
|
||||
'ssh.zmodem.titleSend': 'Upload to server',
|
||||
'ssh.zmodem.pickDir': 'Choose save folder',
|
||||
'ssh.zmodem.pickFiles': 'Choose files',
|
||||
'ssh.zmodem.receiveDesc':
|
||||
'An sz download request was detected (the remote side is sending files). Choose the local folder to save them in.',
|
||||
'ssh.zmodem.sendDesc':
|
||||
'An rz upload request was detected (the remote side is receiving files). Choose the files to upload.',
|
||||
|
||||
// File panel (SFTP)
|
||||
'ssh.file.up': 'Parent folder',
|
||||
'ssh.file.refresh': 'Refresh',
|
||||
'ssh.file.uploadFile': 'Upload files',
|
||||
'ssh.file.downloadSelected': 'Download selection',
|
||||
'ssh.file.permOwner': 'Permissions / owner',
|
||||
'ssh.file.open': 'Open',
|
||||
'ssh.file.download': 'Download',
|
||||
'ssh.file.upload': 'Upload…',
|
||||
'ssh.file.rename': 'Rename',
|
||||
'ssh.file.new': 'New',
|
||||
'ssh.file.newFolder': 'New folder',
|
||||
'ssh.file.copyPath': 'Copy path',
|
||||
'ssh.file.copyPathFailed': 'Failed to copy the path',
|
||||
'ssh.file.pathCopied': 'Path copied',
|
||||
'ssh.file.permission': 'Permissions…',
|
||||
'ssh.file.deleteTitle': 'Delete?',
|
||||
'ssh.file.loading': 'Loading…',
|
||||
'ssh.file.empty': 'Empty folder',
|
||||
'ssh.file.modeUnavailable': 'Permissions unavailable',
|
||||
'ssh.file.folderName': 'Folder name',
|
||||
'ssh.file.create': 'Create',
|
||||
'ssh.file.renameTitle': 'Rename {name}',
|
||||
'ssh.file.permTitle': 'Permissions · {name}',
|
||||
'ssh.file.permApplied': 'Permissions applied',
|
||||
'ssh.file.octal': 'Octal',
|
||||
'ssh.file.octalPlaceholder': 'e.g. 755',
|
||||
'ssh.file.keepEmpty': 'Leave empty to keep',
|
||||
'ssh.file.ownerHint': 'Leave UID/GID empty to keep the current owner',
|
||||
'ssh.file.permRowOwner': 'Owner',
|
||||
'ssh.file.permRowGroup': 'Group',
|
||||
'ssh.file.permRowOther': 'Other',
|
||||
'ssh.file.permColRead': 'Read',
|
||||
'ssh.file.permColWrite': 'Write',
|
||||
'ssh.file.permColExec': 'Execute',
|
||||
|
||||
// System monitor
|
||||
'ssh.monitor.collecting': 'Collecting…',
|
||||
'ssh.monitor.interrupted': 'Sampling stopped: {error}',
|
||||
'ssh.monitor.mem': 'Memory',
|
||||
'ssh.monitor.disks': 'Disks',
|
||||
'ssh.monitor.net': 'Network',
|
||||
'ssh.monitor.cores': '{n} cores',
|
||||
'ssh.monitor.loadavg': 'Load {value}',
|
||||
'ssh.monitor.uptime': 'Uptime',
|
||||
'ssh.monitor.uptimeSeconds': '{n}s',
|
||||
'ssh.monitor.uptimeMinutes': '{n} min',
|
||||
'ssh.monitor.uptimeHours': '{h} h {m} min',
|
||||
'ssh.monitor.uptimeDays': '{n} d'
|
||||
}
|
||||
|
||||
export default ssh
|
||||
@@ -0,0 +1,27 @@
|
||||
/** Namespace: terminal (terminal view: context menu, search, paste confirm, toolbar, hints). Owner: workspace/terminal. */
|
||||
const terminal: Record<string, string> = {
|
||||
'terminal.menu.find': 'Find',
|
||||
'terminal.menu.selectAll': 'Select all',
|
||||
'terminal.menu.clear': 'Clear',
|
||||
'terminal.search.placeholder': 'Search',
|
||||
'terminal.search.prev': 'Previous',
|
||||
'terminal.search.next': 'Next',
|
||||
'terminal.search.found': 'Found',
|
||||
'terminal.search.notFound': 'Not found',
|
||||
'terminal.suggest.hint': '↑/↓ select · Tab accept · Esc close',
|
||||
'terminal.rec.start': 'Start recording',
|
||||
'terminal.rec.stop': 'Stop recording',
|
||||
'terminal.rec.startLog': 'Start session log',
|
||||
'terminal.rec.stopLog': 'Stop session log',
|
||||
'terminal.rec.openLogs': 'Open logs folder',
|
||||
'terminal.rec.openCwd': 'Open working directory',
|
||||
'terminal.paste.title': 'Confirm paste',
|
||||
'terminal.paste.message': 'Multi-line or potentially risky input detected. Paste it into the terminal?',
|
||||
'terminal.paste.noPrompt': "Don't ask again this session",
|
||||
'terminal.paste.disableDetection': 'Disable paste detection from now on',
|
||||
'terminal.paste.hint':
|
||||
'You can turn it back on or change the detection policy in the general terminal settings.',
|
||||
'terminal.dead.message': 'Process exited (code {code})'
|
||||
}
|
||||
|
||||
export default terminal
|
||||
@@ -0,0 +1,61 @@
|
||||
/** Namespace: workspace (workspace shell: sidebar, tabs, layout menu, split, empty states). Owner: workspace. */
|
||||
const workspace: Record<string, string> = {
|
||||
'workspace.tab.terminalTitle': 'Terminal {n}',
|
||||
'workspace.tab.localTerminal': 'Local terminal',
|
||||
'workspace.tab.closeOthers': 'Close others',
|
||||
'workspace.tab.closeRight': 'Close to the right',
|
||||
'workspace.tab.broadcastTarget': 'Broadcast target',
|
||||
'workspace.tab.broadcastBadge': 'B',
|
||||
'workspace.tab.addInSplit': 'New terminal in this split',
|
||||
'workspace.newTerminal': 'New terminal',
|
||||
'workspace.empty.terminalTitle': 'No terminals',
|
||||
'workspace.empty.sshTitle': 'No SSH sessions',
|
||||
'workspace.empty.sshHint': 'Connect from the server list on the left',
|
||||
'workspace.rail.hideSidebar': 'Collapse sidebar',
|
||||
'workspace.rail.showSidebar': 'Expand sidebar',
|
||||
'workspace.rail.layout': 'Layout',
|
||||
'workspace.rail.settings': 'Settings',
|
||||
'workspace.rail.connecting': 'Connecting…',
|
||||
'workspace.rail.terminalWorkspace': 'Terminal workspace',
|
||||
'workspace.rail.sshWorkspace': 'SSH workspace',
|
||||
'workspace.panel.hideSidebar': 'Collapse sidebar',
|
||||
'workspace.panel.showSidebar': 'Expand sidebar',
|
||||
'workspace.layout.splitRight': 'Split horizontally',
|
||||
'workspace.layout.splitBelow': 'Split vertically',
|
||||
'workspace.layout.saveTemplate': 'Save as template',
|
||||
'workspace.layout.applyTemplate': 'Apply template',
|
||||
'workspace.template.saveTitle': 'Save layout template',
|
||||
'workspace.template.namePlaceholder': 'Template name',
|
||||
'workspace.template.applyTitle': 'Apply layout template',
|
||||
'workspace.template.empty': 'No saved templates',
|
||||
'workspace.template.apply': 'Apply',
|
||||
'workspace.template.deleteConfirm': 'Delete this template?',
|
||||
'workspace.broadcast.toggle': 'Broadcast input',
|
||||
'workspace.broadcast.activeTitle': 'Broadcasting ({count} targets)',
|
||||
'workspace.broadcast.popoverTerminal': 'Broadcast input (Terminal)',
|
||||
'workspace.broadcast.popoverSsh': 'Broadcast input (SSH)',
|
||||
'workspace.broadcast.switch': 'Broadcast switch',
|
||||
'workspace.broadcast.enabled': 'Enabled ({count})',
|
||||
'workspace.broadcast.needTwo': 'Select at least 2 targets',
|
||||
'workspace.broadcast.disabled': 'Disabled',
|
||||
'workspace.broadcast.emptySsh': 'No SSH server sessions',
|
||||
'workspace.broadcast.emptyTerminal': 'No terminals',
|
||||
'workspace.broadcast.hint':
|
||||
'Broadcasting turns on automatically once 2 or more terminals are picked, and turns off once fewer than 2 remain. Only sessions in the current mode can be picked.',
|
||||
'workspace.hint.sshFromList': 'Connect SSH sessions from the server list',
|
||||
'workspace.hint.connectSshFirst': 'Connect to an SSH server first',
|
||||
'workspace.hint.noActiveTerminal': 'No active terminal — open at least one local terminal or SSH session',
|
||||
'workspace.hint.noSessionInPanel': 'The active pane has no session available',
|
||||
'workspace.connect.failed': 'SSH connection failed',
|
||||
'workspace.connect.passwordTitle': 'Enter connection password',
|
||||
'workspace.connect.passwordPlaceholder': 'Password',
|
||||
'workspace.connect.passphraseTitle': 'Enter private key passphrase',
|
||||
'workspace.connect.passphrasePlaceholder': 'Passphrase',
|
||||
'workspace.connect.connecting': 'Connecting…',
|
||||
'workspace.connect.connectingNamed': 'Connecting to {name}',
|
||||
'workspace.connect.action': 'Connect',
|
||||
'workspace.error.title': 'The interface hit an error',
|
||||
'workspace.error.reload': 'Reload'
|
||||
}
|
||||
|
||||
export default workspace
|
||||
Reference in new issue
Block a user