From 0814d442075a3b8d3ebc1ca2ff82db417587789b Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Sat, 8 Jan 2022 16:02:56 +0100 Subject: [PATCH] Translation infrastructure --- .gitignore | 2 + locale/STOP.txt | 3 + locale/af.po | 196 +++ locale/app.pot | 1303 +++++++++++++++++ locale/ar.po | 196 +++ locale/ca.po | 196 +++ locale/cs.po | 196 +++ locale/da.po | 196 +++ locale/de.po | 196 +++ locale/el.po | 196 +++ locale/en.po | 196 +++ locale/es.po | 196 +++ locale/fi.po | 196 +++ locale/fr.po | 196 +++ locale/he.po | 196 +++ locale/hu.po | 196 +++ locale/it.po | 196 +++ locale/ja.po | 196 +++ locale/ko.po | 196 +++ locale/nl.po | 196 +++ locale/no.po | 196 +++ locale/pl.po | 196 +++ locale/pt.po | 196 +++ locale/ro.po | 196 +++ locale/ru.po | 196 +++ locale/sr.po | 196 +++ locale/sv.po | 196 +++ locale/tr.po | 196 +++ locale/uk.po | 196 +++ locale/vi.po | 196 +++ locale/zh.po | 196 +++ package.json | 9 +- scripts/i18n-extract.js | 28 + tabby-core/package.json | 3 + tabby-core/src/api/index.ts | 1 + tabby-core/src/buttonProvider.ts | 4 +- .../components/renameTabModal.component.pug | 4 +- .../components/safeModeModal.component.pug | 4 +- .../src/components/startPage.component.pug | 6 +- .../components/transfersMenu.component.pug | 2 +- .../src/components/transfersMenu.component.ts | 13 +- .../components/unlockVaultModal.component.pug | 11 +- .../src/components/welcomeTab.component.pug | 12 +- .../src/components/welcomeTab.component.ts | 4 +- tabby-core/src/configDefaults.yaml | 1 + tabby-core/src/hotkeys.ts | 92 +- tabby-core/src/index.ts | 44 +- tabby-core/src/profiles.ts | 4 +- tabby-core/src/services/config.service.ts | 17 +- .../src/services/fileProviders.service.ts | 15 +- tabby-core/src/services/locale.service.ts | 134 ++ tabby-core/src/services/profiles.service.ts | 16 +- tabby-core/src/tabContextMenu.ts | 47 +- tabby-core/src/theme.ts | 19 +- tabby-core/src/utils.ts | 15 +- tabby-core/yarn.lock | 55 + tabby-electron/src/hotkeys.ts | 8 +- .../src/services/platform.service.ts | 5 +- .../src/services/updater.service.ts | 10 +- tabby-linkifier/src/decorator.ts | 7 +- tabby-local/src/buttonProvider.ts | 5 +- .../commandLineEditor.component.pug | 8 +- .../environmentEditor.component.pug | 6 +- .../localProfileSettings.component.pug | 6 +- .../components/shellSettingsTab.component.pug | 10 +- .../src/components/terminalTab.component.ts | 13 +- tabby-local/src/hotkeys.ts | 6 +- tabby-local/src/profiles.ts | 5 +- tabby-local/src/services/dockMenu.service.ts | 5 +- tabby-local/src/shells/linuxDefault.ts | 7 +- tabby-local/src/shells/macDefault.ts | 5 +- tabby-local/src/shells/winDefault.ts | 5 +- tabby-local/src/tabContextMenu.ts | 20 +- .../pluginsSettingsTab.component.pug | 35 +- .../serialProfileSettings.component.pug | 22 +- .../src/components/serialTab.component.pug | 4 +- .../src/components/serialTab.component.ts | 19 +- tabby-serial/src/hotkeys.ts | 8 +- tabby-serial/src/profiles.ts | 22 +- tabby-settings/src/buttonProvider.ts | 5 +- .../configSyncSettingsTab.component.pug | 38 +- .../configSyncSettingsTab.component.ts | 25 +- .../components/editProfileModal.component.pug | 18 +- .../components/hotkeyInputModal.component.pug | 4 +- .../hotkeySettingsTab.component.pug | 2 +- .../components/multiHotkeyInput.component.pug | 2 +- .../profilesSettingsTab.component.pug | 24 +- .../profilesSettingsTab.component.ts | 38 +- .../components/releaseNotesTab.component.ts | 6 +- .../setVaultPassphraseModal.component.pug | 8 +- .../src/components/settingsTab.component.pug | 77 +- .../src/components/settingsTab.component.ts | 6 +- .../components/vaultSettingsTab.component.pug | 34 +- .../components/vaultSettingsTab.component.ts | 20 +- .../windowSettingsTab.component.pug | 92 +- tabby-settings/src/hotkeys.ts | 6 +- tabby-settings/src/settings.ts | 17 +- ...keyboardInteractiveAuthPanel.component.pug | 2 +- .../components/sftpDeleteModal.component.pug | 4 +- .../src/components/sftpPanel.component.pug | 8 +- .../sshPortForwardingConfig.component.pug | 18 +- .../sshPortForwardingModal.component.pug | 2 +- .../sshProfileSettings.component.pug | 85 +- .../components/sshSettingsTab.component.pug | 24 +- tabby-ssh/src/components/sshTab.component.pug | 10 +- tabby-ssh/src/components/sshTab.component.ts | 14 +- tabby-ssh/src/hotkeys.ts | 8 +- tabby-ssh/src/profiles.ts | 7 +- tabby-ssh/src/session/ssh.ts | 19 +- tabby-ssh/src/sftpContextMenu.ts | 12 +- tabby-ssh/src/tabContextMenu.ts | 7 +- .../telnetProfileSettings.component.pug | 8 +- .../src/components/telnetTab.component.pug | 2 +- .../src/components/telnetTab.component.ts | 11 +- tabby-telnet/src/hotkeys.ts | 6 +- tabby-telnet/src/profiles.ts | 10 +- .../src/api/baseTerminalTab.component.ts | 23 +- .../appearanceSettingsTab.component.pug | 26 +- .../components/baseTerminalTab.component.pug | 4 +- .../colorSchemeSettingsTab.component.pug | 12 +- .../colorSchemeSettingsTab.component.ts | 10 +- .../loginScriptsSettings.component.pug | 8 +- .../loginScriptsSettings.component.ts | 10 +- .../src/components/searchPanel.component.pug | 2 +- .../src/components/searchPanel.component.ts | 7 +- .../streamProcessingSettings.component.pug | 20 +- .../streamProcessingSettings.component.ts | 47 +- .../terminalSettingsTab.component.pug | 78 +- tabby-terminal/src/hotkeys.ts | 36 +- tabby-terminal/src/settings.ts | 13 +- tabby-terminal/src/tabContextMenu.ts | 13 +- tabby-web/src/services/hostWindow.service.ts | 5 +- webpack.plugin.config.js | 8 + yarn.lock | 428 +++--- 134 files changed, 8137 insertions(+), 889 deletions(-) create mode 100644 locale/STOP.txt create mode 100644 locale/af.po create mode 100644 locale/app.pot create mode 100644 locale/ar.po create mode 100644 locale/ca.po create mode 100644 locale/cs.po create mode 100644 locale/da.po create mode 100644 locale/de.po create mode 100644 locale/el.po create mode 100644 locale/en.po create mode 100644 locale/es.po create mode 100644 locale/fi.po create mode 100644 locale/fr.po create mode 100644 locale/he.po create mode 100644 locale/hu.po create mode 100644 locale/it.po create mode 100644 locale/ja.po create mode 100644 locale/ko.po create mode 100644 locale/nl.po create mode 100644 locale/no.po create mode 100644 locale/pl.po create mode 100644 locale/pt.po create mode 100644 locale/ro.po create mode 100644 locale/ru.po create mode 100644 locale/sr.po create mode 100644 locale/sv.po create mode 100644 locale/tr.po create mode 100644 locale/uk.po create mode 100644 locale/vi.po create mode 100644 locale/zh.po create mode 100755 scripts/i18n-extract.js create mode 100644 tabby-core/src/services/locale.service.ts diff --git a/.gitignore b/.gitignore index fae220ba..c230b70c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ sentry-symbols.js tabby-ssh/util/pagent.exe *.psd + +crowdin.yml diff --git a/locale/STOP.txt b/locale/STOP.txt new file mode 100644 index 00000000..223f9943 --- /dev/null +++ b/locale/STOP.txt @@ -0,0 +1,3 @@ +Do not submit pull requests for translations. + +Translations are managed at https://crowdin.com/project/tabby diff --git a/locale/af.po b/locale/af.po new file mode 100644 index 00000000..449d124d --- /dev/null +++ b/locale/af.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: af\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Afrikaans\n" +"Language: af_ZA\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/app.pot b/locale/app.pot new file mode 100644 index 00000000..eb3b3ffe --- /dev/null +++ b/locale/app.pot @@ -0,0 +1,1303 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "\"{command}\" is still running. Close?" +msgstr "" + +msgid "A second font family used to display characters missing in the main font" +msgstr "" + +msgid "Abort all" +msgstr "" + +msgid "Acrylic background" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Add a private key" +msgstr "" + +msgid "Add..." +msgstr "" + +msgid "Additional space between lines" +msgstr "" + +msgid "Advanced" +msgstr "" + +msgid "Agent" +msgstr "" + +msgid "Agent forwarding" +msgstr "" + +msgid "Agent pipe path" +msgstr "" + +msgid "Agent type" +msgstr "" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Appearance" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "" +"Are you sure you want to close Tabby? You can disable this prompt in " +"Settings -> Window." +msgstr "" + +msgid "Are you sure?" +msgstr "" + +msgid "Arguments" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Ask before closing the browser tab" +msgstr "" + +msgid "Authentication method" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Automatic" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Background type" +msgstr "" + +msgid "Baud rate" +msgstr "" + +msgid "Beginning of the line" +msgstr "" + +msgid "Blink cursor" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Blur" +msgstr "" + +msgid "Bottom" +msgstr "" + +msgid "Built-in" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Change baud rate" +msgstr "" + +msgid "Change the master passphrase" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Ciphers" +msgstr "" + +msgid "Clear recent profiles" +msgstr "" + +msgid "Clear terminal" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close and never show again" +msgstr "" + +msgid "Close focused pane" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tab" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Color scheme" +msgstr "" + +msgid "Command line" +msgstr "" + +msgid "Command's stdin/stdout is used instead of a network connection" +msgstr "" + +msgid "Compact" +msgstr "" + +msgid "Config downloaded" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Config sync" +msgstr "" + +msgid "Config uploaded" +msgstr "" + +msgid "Connect through a proxy server" +msgstr "" + +msgid "Connect to \"%s\"..." +msgstr "" + +msgid "Connect to a different host first and use it as a proxy" +msgstr "" + +msgid "Connecting" +msgstr "" + +msgid "Connection" +msgstr "" + +msgid "Copied" +msgstr "" + +msgid "Copy" +msgstr "" + +msgid "Copy current path" +msgstr "" + +msgid "Copy to clipboard" +msgstr "" + +msgid "Could not decrypt config" +msgstr "" + +msgid "Current" +msgstr "" + +msgid "Current color scheme" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Cursor shape" +msgstr "" + +msgid "Custom CSS" +msgstr "" + +msgid "Data bits" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Default profile for new tabs" +msgstr "" + +msgid "Default profile settings" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Delete" +msgstr "" + +msgid "Delete \"{name}\"?" +msgstr "" + +msgid "Delete next word" +msgstr "" + +msgid "Delete previous word" +msgstr "" + +msgid "Delete the group's profiles?" +msgstr "" + +msgid "Delete this script?" +msgstr "" + +msgid "Delete vault contents?" +msgstr "" + +msgid "Delete {fullPath}?" +msgstr "" + +msgid "Deleting" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Direct" +msgstr "" + +msgid "Disable GPU acceleration" +msgstr "" + +msgid "Disconnect" +msgstr "" + +msgid "Disconnect from {host}?" +msgstr "" + +msgid "Display on" +msgstr "" + +msgid "Do not abort" +msgstr "" + +msgid "Do not close" +msgstr "" + +msgid "Dock always on top" +msgstr "" + +msgid "Dock the terminal" +msgstr "" + +msgid "Docked terminal size" +msgstr "" + +msgid "Docked terminal space" +msgstr "" + +msgid "Docking" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Duplicate as administrator" +msgstr "" + +msgid "Duplicate tab" +msgstr "" + +msgid "Dynamic" +msgstr "" + +msgid "Edit" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "Enable font ligatures" +msgstr "" + +msgid "Enable global hotkey (Ctrl-Space)" +msgstr "" + +msgid "Enables the experimental Windows ConPTY API" +msgstr "" + +msgid "Encrypt config file" +msgstr "" + +msgid "End of the line" +msgstr "" + +msgid "English" +msgstr "" + +msgid "Environment" +msgstr "" + +msgid "Erase config" +msgstr "" + +msgid "Erase the Vault" +msgstr "" + +msgid "Exact match" +msgstr "" + +msgid "Example:" +msgstr "" + +msgid "Export" +msgstr "" + +msgid "Fallback font" +msgstr "" + +msgid "File transfers" +msgstr "" + +msgid "File: {description}" +msgstr "" + +msgid "Fixed" +msgstr "" + +msgid "Focus all panes" +msgstr "" + +msgid "Focus all panes at once (broadcast)" +msgstr "" + +msgid "Focus next pane" +msgstr "" + +msgid "Focus previous pane" +msgstr "" + +msgid "Focus the pane above" +msgstr "" + +msgid "Focus the pane below" +msgstr "" + +msgid "Focus the pane on the left" +msgstr "" + +msgid "Focus the pane on the right" +msgstr "" + +msgid "Font" +msgstr "" + +msgid "Force CR" +msgstr "" + +msgid "Force CRLF" +msgstr "" + +msgid "Force LF" +msgstr "" + +msgid "Forces a specific SSH agent connection type." +msgstr "" + +msgid "Forget" +msgstr "" + +msgid "Forward port" +msgstr "" + +msgid "Forwarded ports" +msgstr "" + +msgid "French" +msgstr "" + +msgid "From color scheme" +msgstr "" + +msgid "From theme" +msgstr "" + +msgid "Full" +msgstr "" + +msgid "General" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Gives the window a blurred transparent background" +msgstr "" + +msgid "Go up" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Help track the number of Tabby installs across the world!" +msgstr "" + +msgid "Hexadecimal" +msgstr "" + +msgid "Hide dock on blur" +msgstr "" + +msgid "Hide tab close button" +msgstr "" + +msgid "Hide tab index" +msgstr "" + +msgid "Hides the docked terminal when you click away." +msgstr "" + +msgid "Host" +msgstr "" + +msgid "Host key" +msgstr "" + +msgid "Hotkeys" +msgstr "" + +msgid "If disabled, only custom profiles will show up in the profile selector" +msgstr "" + +msgid "Immediately echoes your input locally" +msgstr "" + +msgid "Input is sent as you type" +msgstr "" + +msgid "Input mode" +msgstr "" + +msgid "Input newlines" +msgstr "" + +msgid "Installing the update will close all tabs and restart Tabby." +msgstr "" + +msgid "Intelligent Ctrl-C (copy/abort)" +msgstr "" + +msgid "Interactive" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Jump host" +msgstr "" + +msgid "Jump to next word" +msgstr "" + +msgid "Jump to previous word" +msgstr "" + +msgid "Keep" +msgstr "" + +msgid "Keep Alive Interval (Milliseconds)" +msgstr "" + +msgid "Keep docked terminal always on top" +msgstr "" + +msgid "Key" +msgstr "" + +msgid "Key exchange" +msgstr "" + +msgid "Keyboard-interactive auth" +msgstr "" + +msgid "Kill" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Launch WinSCP" +msgstr "" + +msgid "Launch WinSCP for current SSH session" +msgstr "" + +msgid "Learn how to allow Tabby to detect remote shell's working directory." +msgstr "" + +msgid "Left" +msgstr "" + +msgid "Line by line" +msgstr "" + +msgid "Line editor, input is sent after you press Enter" +msgstr "" + +msgid "Line padding" +msgstr "" + +msgid "Loading" +msgstr "" + +msgid "Local" +msgstr "" + +msgid "Local echo" +msgstr "" + +msgid "Local terminal" +msgstr "" + +msgid "Login scripts" +msgstr "" + +msgid "Manage profiles" +msgstr "" + +msgid "Max Keep Alive Count" +msgstr "" + +msgid "Maximize the active pane" +msgstr "" + +msgid "Move tab to the left" +msgstr "" + +msgid "Move tab to the right" +msgstr "" + +msgid "Move to \"Ungrouped\"" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Name for the new config" +msgstr "" + +msgid "Named pipe" +msgstr "" + +msgid "Native" +msgstr "" + +msgid "New admin tab" +msgstr "" + +msgid "New config on {platform}" +msgstr "" + +msgid "New item" +msgstr "" + +msgid "New name" +msgstr "" + +msgid "New profile" +msgstr "" + +msgid "New profile name" +msgstr "" + +msgid "New tab" +msgstr "" + +msgid "New terminal" +msgstr "" + +msgid "New window" +msgstr "" + +msgid "New with profile" +msgstr "" + +msgid "Next tab" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "" + +msgid "Not found" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "OS default" +msgstr "" + +msgid "OS default ({name})" +msgstr "" + +msgid "Off" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Opacity" +msgstr "" + +msgid "Open" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Open SFTP panel" +msgstr "" + +msgid "Open Settings" +msgstr "" + +msgid "Optional" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Output is shown as a hexdump" +msgstr "" + +msgid "Output is shown as it is received" +msgstr "" + +msgid "Output mode" +msgstr "" + +msgid "Output newlines" +msgstr "" + +msgid "Override X11 display" +msgstr "" + +msgid "Overwrite local and sync" +msgstr "" + +msgid "Overwrite remote and sync" +msgstr "" + +msgid "Overwrite the config on the remote side and start syncing?" +msgstr "" + +msgid "Overwrite the local config and start syncing?" +msgstr "" + +msgid "Paper" +msgstr "" + +msgid "Parity" +msgstr "" + +msgid "Passphrase for a private key with hash {hash}..." +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Paste" +msgstr "" + +msgid "Paste from clipboard" +msgstr "" + +msgid "Paste multiple lines?" +msgstr "" + +msgid "Path or address of the local X11 socket" +msgstr "" + +msgid "Pin" +msgstr "" + +msgid "Port" +msgstr "" + +msgid "Port opened" +msgstr "" + +msgid "Ports" +msgstr "" + +msgid "Press any key to reconnect" +msgstr "" + +msgid "Press the key now" +msgstr "" + +msgid "Prevents accidental closing" +msgstr "" + +msgid "Previous tab" +msgstr "" + +msgid "Private keys" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Profiles" +msgstr "" + +msgid "Profiles & connections" +msgstr "" + +msgid "Profiles and connections" +msgstr "" + +msgid "Program" +msgstr "" + +msgid "Proxy command" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Puts all of Tabby's configuration into the vault" +msgstr "" + +msgid "Quick connect" +msgstr "" + +msgid "Quit" +msgstr "" + +msgid "Raw socket connection" +msgstr "" + +msgid "Ready Timeout (Milliseconds)" +msgstr "" + +msgid "Recent" +msgstr "" + +msgid "Reconnect" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Regex" +msgstr "" + +msgid "Release notes" +msgstr "" + +msgid "Remote" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Rename Tab" +msgstr "" + +msgid "Reopen last tab" +msgstr "" + +msgid "Replace" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Reset zoom" +msgstr "" + +msgid "Restart current SSH session" +msgstr "" + +msgid "Restart current Telnet session" +msgstr "" + +msgid "Restart current serial session" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Reuse session for multiple tabs" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Run as administrator" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "SFTP" +msgstr "" + +msgid "SOCKS proxy" +msgstr "" + +msgid "SOCKS proxy host" +msgstr "" + +msgid "SOCKS proxy port" +msgstr "" + +msgid "SSH connection" +msgstr "" + +msgid "SSH connection management is now done through the" +msgstr "" + +msgid "SSH password for {user}@{host}:{port}" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Save a password in the keychain" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save as profile" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Saved" +msgstr "" + +msgid "Saved layout" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Select a base profile to use as a template" +msgstr "" + +msgid "Select file storage" +msgstr "" + +msgid "Select profile" +msgstr "" + +msgid "Select profile or enter an address" +msgstr "" + +msgid "Send bytes by typing in hex values" +msgstr "" + +msgid "Sends data one byte at a time" +msgstr "" + +msgid "Serial" +msgstr "" + +msgid "Serial connection" +msgstr "" + +msgid "Serial: {description}" +msgstr "" + +msgid "Set master passphrase" +msgstr "" + +msgid "Set passphrase" +msgstr "" + +msgid "Set password" +msgstr "" + +msgid "Set to 0 to disable recent profiles" +msgstr "" + +msgid "Sets the SSH agent's named pipe path." +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Shell" +msgstr "" + +msgid "Shell does not support current path detection" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show Serial connections" +msgstr "" + +msgid "Show built-in profiles in selector" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show pane labels (for rearranging)" +msgstr "" + +msgid "Show profile selector" +msgstr "" + +msgid "Show recent profiles in selector" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Show vault contents" +msgstr "" + +msgid "Skip MoTD/banner" +msgstr "" + +msgid "Slow feed" +msgstr "" + +msgid "Snaps the window to a side of the screen" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Split to the bottom" +msgstr "" + +msgid "Split to the left" +msgstr "" + +msgid "Split to the right" +msgstr "" + +msgid "Split to the top" +msgstr "" + +msgid "Standard" +msgstr "" + +msgid "Stop bits" +msgstr "" + +msgid "Strip" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Substitutions allowed." +msgstr "" + +msgid "Switch profile" +msgstr "" + +msgid "Switch profile in the active pane" +msgstr "" + +msgid "Tab 1" +msgstr "" + +msgid "Tab 10" +msgstr "" + +msgid "Tab 11" +msgstr "" + +msgid "Tab 12" +msgstr "" + +msgid "Tab 13" +msgstr "" + +msgid "Tab 14" +msgstr "" + +msgid "Tab 15" +msgstr "" + +msgid "Tab 16" +msgstr "" + +msgid "Tab 17" +msgstr "" + +msgid "Tab 18" +msgstr "" + +msgid "Tab 19" +msgstr "" + +msgid "Tab 2" +msgstr "" + +msgid "Tab 20" +msgstr "" + +msgid "Tab 3" +msgstr "" + +msgid "Tab 4" +msgstr "" + +msgid "Tab 5" +msgstr "" + +msgid "Tab 6" +msgstr "" + +msgid "Tab 7" +msgstr "" + +msgid "Tab 8" +msgstr "" + +msgid "Tab 9" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "" +"Tabby could not start with your plugins, so all third party plugins have " +"been disabled in this session. The error was:" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Tabs" +msgstr "" + +msgid "Tabs location" +msgstr "" + +msgid "Tabs width" +msgstr "" + +msgid "Telnet" +msgstr "" + +msgid "Telnet session" +msgstr "" + +msgid "Terminal" +msgstr "" + +msgid "Terminal background" +msgstr "" + +msgid "Thank you for downloading Tabby!" +msgstr "" + +msgid "Theme" +msgstr "" + +msgid "There are active file transfers" +msgstr "" + +msgid "There is a saved password for this connection" +msgstr "" + +msgid "These apply to all profiles of a given type" +msgstr "" + +msgid "Thin" +msgstr "" + +msgid "Tick this if you're experiencing aliasing, ghosting or other visual issues" +msgstr "" + +msgid "Toggle fullscreen mode" +msgstr "" + +msgid "Toggle last tab" +msgstr "" + +msgid "Toggle terminal window" +msgstr "" + +msgid "Toggles the Tabby window visibility" +msgstr "" + +msgid "Top" +msgstr "" + +msgid "Try again" +msgstr "" + +msgid "Trying saved password" +msgstr "" + +msgid "Ungrouped" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unknown secret of type {type} for {key}" +msgstr "" + +msgid "Unpin" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "Upload" +msgstr "" + +msgid "Use ConPTY" +msgstr "" + +msgid "User default" +msgstr "" + +msgid "Username" +msgstr "" + +msgid "Using preset password" +msgstr "" + +msgid "Vault" +msgstr "" + +msgid "" +"Vault is an always-encrypted container for secrets such as SSH passwords " +"and private key passphrases." +msgstr "" + +msgid "Vault is empty" +msgstr "" + +msgid "Vault is locked" +msgstr "" + +msgid "Vault is not configured" +msgstr "" + +msgid "Vault master passphrase needs to be set to allow storing secrets" +msgstr "" + +msgid "Vibrancy" +msgstr "" + +msgid "WSL terminal only supports TrueColor with ConPTY" +msgstr "" + +msgid "Warn when closing active connections" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "Welcome" +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "" +"When WinSCP is detected, you can launch an SCP session from the context " +"menu." +msgstr "" + +msgid "Whether a custom window or an OS native window should be used" +msgstr "" + +msgid "WinSCP path" +msgstr "" + +msgid "Window" +msgstr "" + +msgid "Window frame" +msgstr "" + +msgid "Windows 10 build 18309 or above is recommended for ConPTY" +msgstr "" + +msgid "Working directory" +msgstr "" + +msgid "Working directory detection" +msgstr "" + +msgid "X11 forwarding" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "You can change it later, but it's unrecoverable if forgotten." +msgstr "" + +msgid "Zoom in" +msgstr "" + +msgid "Zoom out" +msgstr "" + +msgid "click" +msgstr "" + +msgid "tab" +msgstr "" + +msgid "{name} copy" +msgstr "" \ No newline at end of file diff --git a/locale/ar.po b/locale/ar.po new file mode 100644 index 00000000..66c0ffef --- /dev/null +++ b/locale/ar.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ar\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Arabic\n" +"Language: ar_SA\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/ca.po b/locale/ca.po new file mode 100644 index 00000000..692fd8fb --- /dev/null +++ b/locale/ca.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ca\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Catalan\n" +"Language: ca_ES\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/cs.po b/locale/cs.po new file mode 100644 index 00000000..0473d72c --- /dev/null +++ b/locale/cs.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: cs\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Czech\n" +"Language: cs_CZ\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/da.po b/locale/da.po new file mode 100644 index 00000000..fdc27470 --- /dev/null +++ b/locale/da.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: da\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Danish\n" +"Language: da_DK\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/de.po b/locale/de.po new file mode 100644 index 00000000..20c86794 --- /dev/null +++ b/locale/de.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: de\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: German\n" +"Language: de_DE\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/el.po b/locale/el.po new file mode 100644 index 00000000..356a2035 --- /dev/null +++ b/locale/el.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: el\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Greek\n" +"Language: el_GR\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/en.po b/locale/en.po new file mode 100644 index 00000000..16ca1204 --- /dev/null +++ b/locale/en.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: en\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: English\n" +"Language: en_US\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/es.po b/locale/es.po new file mode 100644 index 00000000..f249df5d --- /dev/null +++ b/locale/es.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: es-ES\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Spanish\n" +"Language: es_ES\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/fi.po b/locale/fi.po new file mode 100644 index 00000000..e5c167bd --- /dev/null +++ b/locale/fi.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: fi\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Finnish\n" +"Language: fi_FI\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/fr.po b/locale/fr.po new file mode 100644 index 00000000..1b90fe54 --- /dev/null +++ b/locale/fr.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: fr\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: French\n" +"Language: fr_FR\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/he.po b/locale/he.po new file mode 100644 index 00000000..5b27614b --- /dev/null +++ b/locale/he.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: he\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Hebrew\n" +"Language: he_IL\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/hu.po b/locale/hu.po new file mode 100644 index 00000000..84c050eb --- /dev/null +++ b/locale/hu.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: hu\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Hungarian\n" +"Language: hu_HU\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/it.po b/locale/it.po new file mode 100644 index 00000000..9640dd9c --- /dev/null +++ b/locale/it.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: it\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Italian\n" +"Language: it_IT\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/ja.po b/locale/ja.po new file mode 100644 index 00000000..4571e36a --- /dev/null +++ b/locale/ja.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ja\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Japanese\n" +"Language: ja_JP\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/ko.po b/locale/ko.po new file mode 100644 index 00000000..b3338072 --- /dev/null +++ b/locale/ko.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ko\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Korean\n" +"Language: ko_KR\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/nl.po b/locale/nl.po new file mode 100644 index 00000000..8a2953fb --- /dev/null +++ b/locale/nl.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: nl\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Dutch\n" +"Language: nl_NL\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/no.po b/locale/no.po new file mode 100644 index 00000000..25849fee --- /dev/null +++ b/locale/no.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: no\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Norwegian\n" +"Language: no_NO\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/pl.po b/locale/pl.po new file mode 100644 index 00000000..fcd5f322 --- /dev/null +++ b/locale/pl.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: pl\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Polish\n" +"Language: pl_PL\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/pt.po b/locale/pt.po new file mode 100644 index 00000000..f5f70c9c --- /dev/null +++ b/locale/pt.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: pt-BR\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Portuguese, Brazilian\n" +"Language: pt_BR\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/ro.po b/locale/ro.po new file mode 100644 index 00000000..21a9f16d --- /dev/null +++ b/locale/ro.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ro\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Romanian\n" +"Language: ro_RO\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/ru.po b/locale/ru.po new file mode 100644 index 00000000..536f88c1 --- /dev/null +++ b/locale/ru.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: ru\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Russian\n" +"Language: ru_RU\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "Приложение" + +msgid "Application settings" +msgstr "Настройки приложения" + +msgid "Ask a question" +msgstr "Задать вопрос" + +msgid "Automatic Updates" +msgstr "Автоматическое обновление" + +msgid "Blue" +msgstr "Синий" + +msgid "Check for updates" +msgstr "Проверить обновления" + +msgid "Close" +msgstr "Закрыть" + +msgid "Close other tabs" +msgstr "Закрыть другие вкладки" + +msgid "Close tabs to the left" +msgstr "Закрыть вкладки слева" + +msgid "Close tabs to the right" +msgstr "Закрыть вкладки справа" + +msgid "Color" +msgstr "Цвет" + +msgid "Config file" +msgstr "Файл настроек" + +msgid "Current process: {name}" +msgstr "Текущий процесс: {name}" + +msgid "Debugging" +msgstr "Отладка" + +msgid "Defaults" +msgstr "Значения по умолчанию" + +msgid "Down" +msgstr "Вниз" + +msgid "Duplicate" +msgstr "Дублировать" + +msgid "Enable analytics" +msgstr "Аналитика" + +msgid "Enable automatic installation of updates when they become available." +msgstr "Включить автоматическую установку обновлений, когда они доступны." + +msgid "English" +msgstr "Английский" + +msgid "French" +msgstr "Французский" + +msgid "Generate a pre-filled GitHub issue" +msgstr "Открыть пред-заполненный отчет на GitHub" + +msgid "German" +msgstr "Немецкий" + +msgid "Green" +msgstr "Зеленый" + +msgid "Invalid syntax" +msgstr "Неверный синтаксис" + +msgid "Language" +msgstr "Язык" + +msgid "Left" +msgstr "Налево" + +msgid "No color" +msgstr "Без цвета" + +msgid "Notify on activity" +msgstr "Уведомить об активности" + +msgid "Notify when done" +msgstr "Уведомить о завершении" + +msgid "On GitHub Discussions" +msgstr "На GitHub Discussions" + +msgid "Open DevTools" +msgstr "Открыть DevTools" + +msgid "Orange" +msgstr "Оранжевый" + +msgid "Process completed" +msgstr "Процесс завершен" + +msgid "Profile name" +msgstr "Название профиля" + +msgid "Purple" +msgstr "Фиолетовый" + +msgid "Red" +msgstr "Красный" + +msgid "Rename" +msgstr "Переименовать" + +msgid "Report a problem" +msgstr "Сообщить о проблеме" + +msgid "Restart the app to apply changes" +msgstr "Перезапустите приложение, чтобы применить изменения" + +msgid "Right" +msgstr "Направо" + +msgid "Russian" +msgstr "Русский" + +msgid "Save and apply" +msgstr "Сохранить и применить" + +msgid "Save layout as profile" +msgstr "Сохранить как профиль" + +msgid "Shell integration" +msgstr "Интеграция в систему" + +msgid "Show config file" +msgstr "Показать файл настроек" + +msgid "Show defaults" +msgstr "Показать значения по умолчанию" + +msgid "Show release notes" +msgstr "Посмотреть изменения в релизе" + +msgid "Source code" +msgstr "Исходный код" + +msgid "Split" +msgstr "Разделить" + +msgid "Subscribe to updates" +msgstr "Подпишитесь на обновления" + +msgid "Tab activity" +msgstr "Активность в вкладке" + +msgid "Tabby news and updates on Twitter" +msgstr "Новости и обновления про Tabby в Twitter" + +msgid "Up" +msgstr "Вверх" + +msgid "Update" +msgstr "Обновить" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "Отслеживаем только версию ОС и приложения." + +msgid "What's new" +msgstr "Что нового" + +msgid "Yellow" +msgstr "Желтый" + +msgid "click" +msgstr "" + diff --git a/locale/sr.po b/locale/sr.po new file mode 100644 index 00000000..9553cb91 --- /dev/null +++ b/locale/sr.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: sr\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Serbian (Cyrillic)\n" +"Language: sr_SP\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/sv.po b/locale/sv.po new file mode 100644 index 00000000..15c5d796 --- /dev/null +++ b/locale/sv.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: sv-SE\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Swedish\n" +"Language: sv_SE\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/tr.po b/locale/tr.po new file mode 100644 index 00000000..d185c4ee --- /dev/null +++ b/locale/tr.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: tr\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Turkish\n" +"Language: tr_TR\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/uk.po b/locale/uk.po new file mode 100644 index 00000000..7a325817 --- /dev/null +++ b/locale/uk.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: uk\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Ukrainian\n" +"Language: uk_UA\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/vi.po b/locale/vi.po new file mode 100644 index 00000000..eed8e309 --- /dev/null +++ b/locale/vi.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: vi\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Vietnamese\n" +"Language: vi_VN\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/locale/zh.po b/locale/zh.po new file mode 100644 index 00000000..0fd61108 --- /dev/null +++ b/locale/zh.po @@ -0,0 +1,196 @@ +msgid "" +msgstr "" +"mime-version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: tabby\n" +"X-Crowdin-Project-ID: 493349\n" +"X-Crowdin-Language: zh-TW\n" +"X-Crowdin-File: /locale/app.pot\n" +"X-Crowdin-File-ID: 75\n" +"Project-Id-Version: tabby\n" +"Language-Team: Chinese Traditional\n" +"Language: zh_TW\n" +"PO-Revision-Date: 2022-01-08 12:42\n" + +msgid "Allows quickly opening a terminal in the selected folder" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Application settings" +msgstr "" + +msgid "Ask a question" +msgstr "" + +msgid "Automatic Updates" +msgstr "" + +msgid "Blue" +msgstr "" + +msgid "Check for updates" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Close other tabs" +msgstr "" + +msgid "Close tabs to the left" +msgstr "" + +msgid "Close tabs to the right" +msgstr "" + +msgid "Color" +msgstr "" + +msgid "Config file" +msgstr "" + +msgid "Current process: {name}" +msgstr "" + +msgid "Debugging" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Down" +msgstr "" + +msgid "Duplicate" +msgstr "" + +msgid "Enable analytics" +msgstr "" + +msgid "Enable automatic installation of updates when they become available." +msgstr "" + +msgid "English" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Generate a pre-filled GitHub issue" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Green" +msgstr "" + +msgid "Invalid syntax" +msgstr "" + +msgid "Language" +msgstr "" + +msgid "Left" +msgstr "" + +msgid "No color" +msgstr "" + +msgid "Notify on activity" +msgstr "" + +msgid "Notify when done" +msgstr "" + +msgid "On GitHub Discussions" +msgstr "" + +msgid "Open DevTools" +msgstr "" + +msgid "Orange" +msgstr "" + +msgid "Process completed" +msgstr "" + +msgid "Profile name" +msgstr "" + +msgid "Purple" +msgstr "" + +msgid "Red" +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Report a problem" +msgstr "" + +msgid "Restart the app to apply changes" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Russian" +msgstr "" + +msgid "Save and apply" +msgstr "" + +msgid "Save layout as profile" +msgstr "" + +msgid "Shell integration" +msgstr "" + +msgid "Show config file" +msgstr "" + +msgid "Show defaults" +msgstr "" + +msgid "Show release notes" +msgstr "" + +msgid "Source code" +msgstr "" + +msgid "Split" +msgstr "" + +msgid "Subscribe to updates" +msgstr "" + +msgid "Tab activity" +msgstr "" + +msgid "Tabby news and updates on Twitter" +msgstr "" + +msgid "Up" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "We're only tracking your Tabby and OS versions." +msgstr "" + +msgid "What's new" +msgstr "" + +msgid "Yellow" +msgstr "" + +msgid "click" +msgstr "" + diff --git a/package.json b/package.json index f17f49ff..f439e9d8 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "@angular/forms": "^12.0.0", "@angular/platform-browser": "^12.0.0", "@angular/platform-browser-dynamic": "^12.0.0", + "@biesbjerg/ngx-translate-extract": "^7.0.4", + "@biesbjerg/ngx-translate-extract-marker": "^1.0.0", "@fortawesome/fontawesome-free": "^6.0.0-beta3", "@ng-bootstrap/ng-bootstrap": "^10.0.0", "@sentry/cli": "^1.71.0", @@ -40,7 +42,7 @@ "file-loader": "^6.2.0", "graceful-fs": "^4.2.8", "html-loader": "2.1.2", - "json-loader": "0.5.7", + "json-loader": "^0.5.7", "lru-cache": "^6.0.0", "macos-release": "^3.0.1", "ngx-sortablejs": "^11.1.0", @@ -50,7 +52,9 @@ "npmlog": "6.0.0", "npx": "^10.2.2", "patch-package": "^6.4.7", - "pug": "^3.0.2", + "po-gettext-loader": "^1.0.0", + "pug": "3", + "pug-cli": "^1.0.0-alpha6", "pug-html-loader": "1.1.5", "pug-lint": "^2.6.0", "pug-loader": "^2.4.0", @@ -80,6 +84,7 @@ "zone.js": "^0.11.4" }, "resolutions": { + "*/pug": "^3", "lzma-native": "^8.0.0", "*/node-abi": "^3.5.0", "**/graceful-fs": "^4.2.4" diff --git a/scripts/i18n-extract.js b/scripts/i18n-extract.js new file mode 100755 index 00000000..4f032ca3 --- /dev/null +++ b/scripts/i18n-extract.js @@ -0,0 +1,28 @@ +#!/usr/bin/env node +const sh = require('shelljs') +const fs = require('fs/promises') +const vars = require('./vars') +const log = require('npmlog') + +const tempOutput = 'locale/app.new.pot' +const pot = 'locale/app.pot' +const tempHtml = 'locale/tmp-html' + +;(async () => { + sh.mkdir('-p', tempHtml) + for (const plugin of vars.builtinPlugins) { + log.info('extract-pug', plugin) + + sh.exec(`yarn pug --doctype html -s --pretty -O '{require: function(){}}' -o ${tempHtml}/${plugin} ${plugin}`) + + log.info('extract-ts', plugin) + sh.exec(`node node_modules/.bin/ngx-translate-extract -i ${plugin}/src -m -s -f pot -o ${tempOutput}`) + + } + + log.info('extract-pug') + sh.exec(`node node_modules/.bin/ngx-translate-extract -i ${tempHtml} -f pot -s -o ${tempOutput}`) + + sh.rm('-r', tempHtml) + await fs.rename(tempOutput, pot) +})() diff --git a/tabby-core/package.json b/tabby-core/package.json index c37ba0df..3e5b5675 100644 --- a/tabby-core/package.json +++ b/tabby-core/package.json @@ -17,12 +17,15 @@ "author": "Eugene Pankov", "license": "MIT", "devDependencies": { + "@ngx-translate/core": "^14.0.0", "bootstrap": "^4.1.3", "deepmerge": "^4.1.1", "js-yaml": "^4.0.0", + "messageformat": "^2.3.0", "mixpanel": "^0.13.0", "ngx-filesize": "^2.0.16", "ngx-perfect-scrollbar": "^10.1.0", + "ngx-translate-messageformat-compiler": "^4.11.0", "readable-stream": "3.6.0", "uuid": "^8.0.0" }, diff --git a/tabby-core/src/api/index.ts b/tabby-core/src/api/index.ts index d97630c4..bef85915 100644 --- a/tabby-core/src/api/index.ts +++ b/tabby-core/src/api/index.ts @@ -35,4 +35,5 @@ export { TabsService, NewTabParameters, TabComponentType } from '../services/tab export { UpdaterService } from '../services/updater.service' export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service' export { FileProvidersService } from '../services/fileProviders.service' +export { LocaleService, TranslateServiceWrapper as TranslateService } from '../services/locale.service' export * from '../utils' diff --git a/tabby-core/src/buttonProvider.ts b/tabby-core/src/buttonProvider.ts index 57a17396..cdf5ce0a 100644 --- a/tabby-core/src/buttonProvider.ts +++ b/tabby-core/src/buttonProvider.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Injectable } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { ToolbarButton, ToolbarButtonProvider } from './api/toolbarButtonProvider' import { HostAppService, Platform } from './api/hostApp' @@ -12,6 +13,7 @@ export class ButtonProvider extends ToolbarButtonProvider { constructor ( private hostApp: HostAppService, private profilesService: ProfilesService, + private translate: TranslateService, hotkeys: HotkeysService, ) { super() @@ -35,7 +37,7 @@ export class ButtonProvider extends ToolbarButtonProvider { icon: this.hostApp.platform === Platform.Web ? require('./icons/plus.svg') : require('./icons/profiles.svg'), - title: 'Profiles and connections', + title: this.translate.instant('Profiles and connections'), click: () => this.activate(), }, ...this.profilesService.getRecentProfiles().map(profile => ({ diff --git a/tabby-core/src/components/renameTabModal.component.pug b/tabby-core/src/components/renameTabModal.component.pug index ddc5c358..441aa008 100644 --- a/tabby-core/src/components/renameTabModal.component.pug +++ b/tabby-core/src/components/renameTabModal.component.pug @@ -2,5 +2,5 @@ input.form-control(type='text', #input, [(ngModel)]='value', (keyup.enter)='save()', autofocus) .modal-footer - button.btn.btn-primary((click)='save()') Save - button.btn.btn-secondary((click)='close()') Cancel + button.btn.btn-primary((click)='save()', translate) Save + button.btn.btn-secondary((click)='close()', translate) Cancel diff --git a/tabby-core/src/components/safeModeModal.component.pug b/tabby-core/src/components/safeModeModal.component.pug index fed3c8af..d4a4ab94 100644 --- a/tabby-core/src/components/safeModeModal.component.pug +++ b/tabby-core/src/components/safeModeModal.component.pug @@ -1,7 +1,7 @@ .modal-body - .alert.alert-danger Tabby could not start with your plugins, so all third party plugins have been disabled in this session. The error was: + .alert.alert-danger(translate) Tabby could not start with your plugins, so all third party plugins have been disabled in this session. The error was: pre {{error}} .modal-footer - button.btn.btn-primary((click)='close()') Close + button.btn.btn-primary((click)='close()', translate) Close diff --git a/tabby-core/src/components/startPage.component.pug b/tabby-core/src/components/startPage.component.pug index fbacf475..6d3066ae 100644 --- a/tabby-core/src/components/startPage.component.pug +++ b/tabby-core/src/components/startPage.component.pug @@ -15,9 +15,9 @@ footer.d-flex.align-items-center .btn-group.mr-auto button.btn.btn-dark((click)='homeBase.openGitHub()') i.fab.fa-github - span GitHub + span(translate) GitHub button.btn.btn-dark((click)='homeBase.reportBug()') i.fas.fa-bug - span Report a problem + span(translate) Report a problem - .form-control-static.selectable.no-drag Version: {{homeBase.appVersion}} + .form-control-static.selectable.no-drag(translate, [translateParams]='{version: homeBase.appVersion}') Version: {version} diff --git a/tabby-core/src/components/transfersMenu.component.pug b/tabby-core/src/components/transfersMenu.component.pug index 74fa211f..992977b3 100644 --- a/tabby-core/src/components/transfersMenu.component.pug +++ b/tabby-core/src/components/transfersMenu.component.pug @@ -1,5 +1,5 @@ .d-flex.align-items-center - .dropdown-header File transfers + .dropdown-header(translate) File transfers button.btn.btn-link.ml-auto((click)='removeAll(); $event.stopPropagation()') !{require('../icons/times.svg')} .transfer(*ngFor='let transfer of transfers', (click)='showTransfer(transfer)') .icon(*ngIf='isDownload(transfer)') !{require('../icons/download.svg')} diff --git a/tabby-core/src/components/transfersMenu.component.ts b/tabby-core/src/components/transfersMenu.component.ts index b3b67701..280602c4 100644 --- a/tabby-core/src/components/transfersMenu.component.ts +++ b/tabby-core/src/components/transfersMenu.component.ts @@ -1,4 +1,5 @@ import { Component, Input, Output, EventEmitter } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { FileDownload, FileTransfer, PlatformService } from '../api/platform' /** @hidden */ @@ -11,7 +12,10 @@ export class TransfersMenuComponent { @Input() transfers: FileTransfer[] @Output() transfersChange = new EventEmitter() - constructor (private platform: PlatformService) { } + constructor ( + private platform: PlatformService, + private translate: TranslateService, + ) { } isDownload (transfer: FileTransfer): boolean { return transfer instanceof FileDownload @@ -40,8 +44,11 @@ export class TransfersMenuComponent { if (this.transfers.some(x => !x.isComplete())) { if ((await this.platform.showMessageBox({ type: 'warning', - message: 'There are active file transfers', - buttons: ['Abort all', 'Do not abort'], + message: this.translate.instant('There are active file transfers'), + buttons: [ + this.translate.instant('Abort all'), + this.translate.instant('Do not abort'), + ], defaultId: 1, cancelId: 1, })).response === 1) { diff --git a/tabby-core/src/components/unlockVaultModal.component.pug b/tabby-core/src/components/unlockVaultModal.component.pug index 75c77785..0358872d 100644 --- a/tabby-core/src/components/unlockVaultModal.component.pug +++ b/tabby-core/src/components/unlockVaultModal.component.pug @@ -1,13 +1,18 @@ .modal-body .d-flex.align-items-center.mb-3 - h3.m-0 Vault is locked + h3.m-0(translate) Vault is locked .ml-auto(ngbDropdown, placement='bottom-right') button.btn.btn-link(ngbDropdownToggle, (click)='$event.stopPropagation()') - span(*ngIf='rememberFor') Remember for {{getRememberForDisplay(rememberFor)}} - span(*ngIf='!rememberFor') Do not remember + span( + *ngIf='rememberFor', + translate, + [translateParams]='{time: getRememberForDisplay(rememberFor)}' + ) Remember for {time} + span(*ngIf='!rememberFor', translate) Do not remember div(ngbDropdownMenu) button.dropdown-item( (click)='rememberFor = 0', + translate ) Do not remember button.dropdown-item( *ngFor='let x of rememberOptions', diff --git a/tabby-core/src/components/welcomeTab.component.pug b/tabby-core/src/components/welcomeTab.component.pug index 719824ae..4cff9b32 100644 --- a/tabby-core/src/components/welcomeTab.component.pug +++ b/tabby-core/src/components/welcomeTab.component.pug @@ -4,21 +4,21 @@ h1.tabby-title Tabby sup α - .text-center.mb-5 Thank you for downloading Tabby! + .text-center.mb-5(translate) Thank you for downloading Tabby! .form-line .header - .title Enable analytics - .description Help track the number of Tabby installs across the world! + .title(translate) Enable analytics + .description(translate) Help track the number of Tabby installs across the world! toggle([(ngModel)]='config.store.enableAnalytics') .form-line .header - .title Enable global hotkey (#[strong Ctrl-Space]) - .description Toggles the Tabby window visibility + .title(translate) Enable global hotkey (Ctrl-Space) + .description(translate) Toggles the Tabby window visibility toggle([(ngModel)]='enableGlobalHotkey') .text-center.mt-5 - button.btn.btn-primary((click)='closeAndDisable()') Close and never show again + button.btn.btn-primary((click)='closeAndDisable()', translate) Close and never show again diff --git a/tabby-core/src/components/welcomeTab.component.ts b/tabby-core/src/components/welcomeTab.component.ts index 7a85ad0d..cb623ef8 100644 --- a/tabby-core/src/components/welcomeTab.component.ts +++ b/tabby-core/src/components/welcomeTab.component.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Component } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { BaseTabComponent } from './baseTab.component' import { ConfigService } from '../services/config.service' import { HostWindowService } from '../api/hostWindow' @@ -16,9 +17,10 @@ export class WelcomeTabComponent extends BaseTabComponent { constructor ( private hostWindow: HostWindowService, public config: ConfigService, + translate: TranslateService, ) { super() - this.setTitle('Welcome') + this.setTitle(translate.instant('Welcome')) } async closeAndDisable () { diff --git a/tabby-core/src/configDefaults.yaml b/tabby-core/src/configDefaults.yaml index f0555b2f..6d83d41b 100644 --- a/tabby-core/src/configDefaults.yaml +++ b/tabby-core/src/configDefaults.yaml @@ -38,3 +38,4 @@ enableExperimentalFeatures: false pluginBlacklist: [] hacks: disableGPU: false +language: null diff --git a/tabby-core/src/hotkeys.ts b/tabby-core/src/hotkeys.ts index 9a809ad5..ccac4e3f 100644 --- a/tabby-core/src/hotkeys.ts +++ b/tabby-core/src/hotkeys.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { ProfilesService } from './services/profiles.service' import { HotkeyDescription, HotkeyProvider } from './api/hotkeyProvider' import { PartialProfile, Profile } from './api' @@ -9,188 +10,189 @@ export class AppHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'profile-selector', - name: 'Show profile selector', + name: this.translate.instant('Show profile selector'), }, { id: 'toggle-fullscreen', - name: 'Toggle fullscreen mode', + name: this.translate.instant('Toggle fullscreen mode'), }, { id: 'rename-tab', - name: 'Rename Tab', + name: this.translate.instant('Rename Tab'), }, { id: 'close-tab', - name: 'Close tab', + name: this.translate.instant('Close tab'), }, { id: 'reopen-tab', - name: 'Reopen last tab', + name: this.translate.instant('Reopen last tab'), }, { id: 'toggle-last-tab', - name: 'Toggle last tab', + name: this.translate.instant('Toggle last tab'), }, { id: 'next-tab', - name: 'Next tab', + name: this.translate.instant('Next tab'), }, { id: 'previous-tab', - name: 'Previous tab', + name: this.translate.instant('Previous tab'), }, { id: 'move-tab-left', - name: 'Move tab to the left', + name: this.translate.instant('Move tab to the left'), }, { id: 'move-tab-right', - name: 'Move tab to the right', + name: this.translate.instant('Move tab to the right'), }, { id: 'rearrange-panes', - name: 'Show pane labels (for rearranging)', + name: this.translate.instant('Show pane labels (for rearranging)'), }, { id: 'duplicate-tab', - name: 'Duplicate tab', + name: this.translate.instant('Duplicate tab'), }, { id: 'tab-1', - name: 'Tab 1', + name: this.translate.instant('Tab 1'), }, { id: 'tab-2', - name: 'Tab 2', + name: this.translate.instant('Tab 2'), }, { id: 'tab-3', - name: 'Tab 3', + name: this.translate.instant('Tab 3'), }, { id: 'tab-4', - name: 'Tab 4', + name: this.translate.instant('Tab 4'), }, { id: 'tab-5', - name: 'Tab 5', + name: this.translate.instant('Tab 5'), }, { id: 'tab-6', - name: 'Tab 6', + name: this.translate.instant('Tab 6'), }, { id: 'tab-7', - name: 'Tab 7', + name: this.translate.instant('Tab 7'), }, { id: 'tab-8', - name: 'Tab 8', + name: this.translate.instant('Tab 8'), }, { id: 'tab-9', - name: 'Tab 9', + name: this.translate.instant('Tab 9'), }, { id: 'tab-10', - name: 'Tab 10', + name: this.translate.instant('Tab 10'), }, { id: 'tab-11', - name: 'Tab 11', + name: this.translate.instant('Tab 11'), }, { id: 'tab-12', - name: 'Tab 12', + name: this.translate.instant('Tab 12'), }, { id: 'tab-13', - name: 'Tab 13', + name: this.translate.instant('Tab 13'), }, { id: 'tab-14', - name: 'Tab 14', + name: this.translate.instant('Tab 14'), }, { id: 'tab-15', - name: 'Tab 15', + name: this.translate.instant('Tab 15'), }, { id: 'tab-16', - name: 'Tab 16', + name: this.translate.instant('Tab 16'), }, { id: 'tab-17', - name: 'Tab 17', + name: this.translate.instant('Tab 17'), }, { id: 'tab-18', - name: 'Tab 18', + name: this.translate.instant('Tab 18'), }, { id: 'tab-19', - name: 'Tab 19', + name: this.translate.instant('Tab 19'), }, { id: 'tab-20', - name: 'Tab 20', + name: this.translate.instant('Tab 20'), }, { id: 'split-right', - name: 'Split to the right', + name: this.translate.instant('Split to the right'), }, { id: 'split-bottom', - name: 'Split to the bottom', + name: this.translate.instant('Split to the bottom'), }, { id: 'split-left', - name: 'Split to the left', + name: this.translate.instant('Split to the left'), }, { id: 'split-top', - name: 'Split to the top', + name: this.translate.instant('Split to the top'), }, { id: 'pane-maximize', - name: 'Maximize the active pane', + name: this.translate.instant('Maximize the active pane'), }, { id: 'pane-nav-up', - name: 'Focus the pane above', + name: this.translate.instant('Focus the pane above'), }, { id: 'pane-nav-down', - name: 'Focus the pane below', + name: this.translate.instant('Focus the pane below'), }, { id: 'pane-nav-left', - name: 'Focus the pane on the left', + name: this.translate.instant('Focus the pane on the left'), }, { id: 'pane-nav-right', - name: 'Focus the pane on the right', + name: this.translate.instant('Focus the pane on the right'), }, { id: 'pane-nav-previous', - name: 'Focus previous pane', + name: this.translate.instant('Focus previous pane'), }, { id: 'pane-nav-next', - name: 'Focus next pane', + name: this.translate.instant('Focus next pane'), }, { id: 'switch-profile', - name: 'Switch profile in the active pane', + name: this.translate.instant('Switch profile in the active pane'), }, { id: 'close-pane', - name: 'Close focused pane', + name: this.translate.instant('Close focused pane'), }, ] constructor ( private profilesService: ProfilesService, + private translate: TranslateService, ) { super() } async provide (): Promise { diff --git a/tabby-core/src/index.ts b/tabby-core/src/index.ts index e2926acb..2218f5cf 100644 --- a/tabby-core/src/index.ts +++ b/tabby-core/src/index.ts @@ -1,4 +1,4 @@ -import { NgModule, ModuleWithProviders } from '@angular/core' +import { NgModule, ModuleWithProviders, LOCALE_ID } from '@angular/core' import { BrowserModule } from '@angular/platform-browser' import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { FormsModule } from '@angular/forms' @@ -7,6 +7,8 @@ import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-sc import { NgxFilesizeModule } from 'ngx-filesize' import { SortablejsModule } from 'ngx-sortablejs' import { DragDropModule } from '@angular/cdk/drag-drop' +import { TranslateModule, TranslateCompiler, TranslateService } from '@ngx-translate/core' +import { TranslateMessageFormatCompiler, MESSAGE_FORMAT_CONFIG } from 'ngx-translate-messageformat-compiler' import { AppRootComponent } from './components/appRoot.component' import { CheckboxComponent } from './components/checkbox.component' @@ -40,6 +42,7 @@ import { AppService } from './services/app.service' import { ConfigService } from './services/config.service' import { VaultFileProvider } from './services/vault.service' import { HotkeysService } from './services/hotkeys.service' +import { LocaleService, TranslateServiceWrapper } from './services/locale.service' import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme' import { CoreConfigProvider } from './config' @@ -51,6 +54,10 @@ import { SplitLayoutProfilesService } from './profiles' import 'perfect-scrollbar/css/perfect-scrollbar.css' +export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler { + return new TranslateMessageFormatCompiler() +} + const PROVIDERS = [ { provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true }, { provide: Theme, useClass: StandardTheme, multi: true }, @@ -68,6 +75,19 @@ const PROVIDERS = [ { provide: FileProvider, useClass: VaultFileProvider, multi: true }, { provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true }, { provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true }, + { + provide: LOCALE_ID, + deps: [LocaleService], + useFactory: locale => locale.getLocale(), + }, + { + provide: MESSAGE_FORMAT_CONFIG, + useValue: LocaleService.allLocales, + }, + { + provide: TranslateService, + useClass: TranslateServiceWrapper, + }, ] /** @hidden */ @@ -81,6 +101,7 @@ const PROVIDERS = [ PerfectScrollbarModule, DragDropModule, SortablejsModule.forRoot({ animation: 150 }), + TranslateModule, ], declarations: [ AppRootComponent, @@ -127,6 +148,7 @@ const PROVIDERS = [ AlwaysVisibleTypeaheadDirective, SortablejsModule, DragDropModule, + TranslateModule, ], }) export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class @@ -135,6 +157,8 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex config: ConfigService, platform: PlatformService, hotkeys: HotkeysService, + public locale: LocaleService, + private translate: TranslateService, private profilesService: ProfilesService, private selector: SelectorService, ) { @@ -182,8 +206,8 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex if (provider.supportsQuickConnect) { options.push({ - name: 'Quick connect', - freeInputPattern: 'Connect to "%s"...', + name: this.translate.instant('Quick connect'), + freeInputPattern: this.translate.instant('Connect to "%s"...'), icon: 'fas fa-arrow-right', callback: query => { const p = provider.quickConnect(query) @@ -194,13 +218,23 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex }) } - await this.selector.show('Select profile', options) + await this.selector.show(this.translate.instant('Select profile'), options) } static forRoot (): ModuleWithProviders { + const translateModule = TranslateModule.forRoot({ + defaultLanguage: 'en', + compiler: { + provide: TranslateCompiler, + useFactory: TranslateMessageFormatCompilerFactory, + }, + }) return { ngModule: AppModule, - providers: PROVIDERS, + providers: [ + ...PROVIDERS, + ...translateModule.providers!.filter(x => x !== TranslateService), + ], } } } diff --git a/tabby-core/src/profiles.ts b/tabby-core/src/profiles.ts index 461539c4..6941f530 100644 --- a/tabby-core/src/profiles.ts +++ b/tabby-core/src/profiles.ts @@ -1,6 +1,7 @@ import slugify from 'slugify' import { v4 as uuidv4 } from 'uuid' import { Injectable } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { ConfigService, NewTabParameters, PartialProfile, Profile, ProfileProvider } from './api' import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component' @@ -15,7 +16,7 @@ export interface SplitLayoutProfile extends Profile { @Injectable({ providedIn: 'root' }) export class SplitLayoutProfilesService extends ProfileProvider { id = 'split-layout' - name = 'Saved layout' + name = this.translate.instant('Saved layout') configDefaults = { options: { recoveryToken: null, @@ -25,6 +26,7 @@ export class SplitLayoutProfilesService extends ProfileProvider ({ - name: p.name, - result: p, - }))) + return this.selector.show( + this.translate.instant('Select file storage'), + providers.map(p => ({ + name: p.name, + result: p, + })) + ) } } diff --git a/tabby-core/src/services/locale.service.ts b/tabby-core/src/services/locale.service.ts new file mode 100644 index 00000000..8278d365 --- /dev/null +++ b/tabby-core/src/services/locale.service.ts @@ -0,0 +1,134 @@ +import { Injectable } from '@angular/core' +import { registerLocaleData } from '@angular/common' +import { TranslateService } from '@ngx-translate/core' + +import localeEN from '@angular/common/locales/en-GB' +import localeRU from '@angular/common/locales/ru' +import { Observable, Subject } from 'rxjs' +import { distinctUntilChanged } from 'rxjs/operators' +import { ConfigService } from './config.service' +import { LogService, Logger } from './log.service' + +registerLocaleData(localeEN) +registerLocaleData(localeRU) + +@Injectable({ providedIn: 'root' }) +export class TranslateServiceWrapper extends TranslateService { + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + getParsedResult (translations: any, key: any, interpolateParams?: any): any { + this.translations[this.defaultLang][key] ??= this.compiler.compile(key, this.defaultLang) + return super.getParsedResult(translations, key, interpolateParams) + } +} + +@Injectable({ providedIn: 'root' }) +export class LocaleService { + private logger: Logger + + static readonly allLocales = ['en', 'de', 'fr', 'ru'] + + get localeChanged$ (): Observable { + return this.localeChanged.pipe(distinctUntilChanged()) + } + + get catalogChanged$ (): Observable> { + return this.catalogChanged.pipe(distinctUntilChanged()) + } + + readonly allLanguages: { code: string, name: string }[] + private translations = { + en: { + Close: 'Close', + }, + ru: { + Close: 'Закрыть', + }, + } + private locale = 'en' + private localeChanged = new Subject() + private catalogChanged = new Subject>() + + constructor ( + private config: ConfigService, + private translate: TranslateService, + log: LogService, + ) { + this.logger = log.create('translate') + config.changed$.subscribe(() => { + this.refresh() + }) + config.ready$.subscribe(() => { + this.refresh() + }) + + this.allLanguages = [ + { + code: 'en', + name: translate.instant('English'), + }, + { + code: 'de', + name: translate.instant('German'), + }, + { + code: 'fr', + name: translate.instant('French'), + }, + /* { + code: 'it', + name: translate.instant('Italian'), + }, + { + code: 'es', + name: translate.instant('Spanish'), + }, */ + { + code: 'ru', + name: translate.instant('Russian'), + }, + /* { + code: 'ar', + name: translate.instant('Arabic'), + }, */ + ] + } + + refresh (): void { + let lang = this.config.store.language + if (!lang) { + const systemLanguage = navigator.language.toLowerCase().split('-')[0] + if (this.allLanguages.some(x => x.code === systemLanguage)) { + lang = systemLanguage + } + } + lang ??= 'en' + this.setLocale(lang) + } + + async setLocale (lang: string): Promise { + const strings = this.translations[lang] + + if (!this.translate.langs.includes(lang)) { + this.translate.addLangs([lang]) + + const po = require(`../../../locale/${lang}.po`).translations[''] + const translation = {} + for (const k of Object.keys(po)) { + translation[k] = po[k].msgstr[0] || k + } + + this.translate.setTranslation(lang, translation) + } + + this.translate.setDefaultLang(lang) + + this.locale = lang + this.localeChanged.next(lang) + this.logger.debug('Setting language to', lang) + this.catalogChanged.next(strings) + } + + getLocale (): string { + return this.locale + } +} diff --git a/tabby-core/src/services/profiles.service.ts b/tabby-core/src/services/profiles.service.ts index ac87efa5..b88bf3f0 100644 --- a/tabby-core/src/services/profiles.service.ts +++ b/tabby-core/src/services/profiles.service.ts @@ -1,4 +1,5 @@ import { Injectable, Inject } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { NewTabParameters } from './tabs.service' import { BaseTabComponent } from '../components/baseTab.component' import { PartialProfile, Profile, ProfileProvider } from '../api/profileProvider' @@ -29,6 +30,7 @@ export class ProfilesService { private config: ConfigService, private notifications: NotificationsService, private selector: SelectorService, + private translate: TranslateService, @Inject(ProfileProvider) private profileProviders: ProfileProvider[], ) { } @@ -103,7 +105,7 @@ export class ProfilesService { let options: SelectorOption[] = recentProfiles.map(p => ({ ...this.selectorOptionForProfile(p), - group: 'Recent', + group: this.translate.instant('Recent'), icon: 'fas fa-history', color: p.color, callback: async () => { @@ -115,8 +117,8 @@ export class ProfilesService { })) if (recentProfiles.length) { options.push({ - name: 'Clear recent profiles', - group: 'Recent', + name: this.translate.instant('Clear recent profiles'), + group: this.translate.instant('Recent'), icon: 'fas fa-eraser', callback: async () => { window.localStorage.removeItem('recentProfiles') @@ -142,7 +144,7 @@ export class ProfilesService { try { const { SettingsTabComponent } = window['nodeRequire']('tabby-settings') options.push({ - name: 'Manage profiles', + name: this.translate.instant('Manage profiles'), icon: 'fas fa-window-restore', callback: () => { this.app.openNewTabRaw({ @@ -156,8 +158,8 @@ export class ProfilesService { if (this.getProviders().some(x => x.supportsQuickConnect)) { options.push({ - name: 'Quick connect', - freeInputPattern: 'Connect to "%s"...', + name: this.translate.instant('Quick connect'), + freeInputPattern: this.translate.instant('Connect to "%s"...'), icon: 'fas fa-arrow-right', callback: query => { const profile = this.quickConnect(query) @@ -165,7 +167,7 @@ export class ProfilesService { }, }) } - await this.selector.show('Select profile or enter an address', options) + await this.selector.show(this.translate.instant('Select profile or enter an address'), options) } catch (err) { reject(err) } diff --git a/tabby-core/src/tabContextMenu.ts b/tabby-core/src/tabContextMenu.ts index d620e8a9..da9dba68 100644 --- a/tabby-core/src/tabContextMenu.ts +++ b/tabby-core/src/tabContextMenu.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Injectable } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { TranslateService } from '@ngx-translate/core' import { Subscription } from 'rxjs' import { AppService } from './services/app.service' import { BaseTabComponent } from './components/baseTab.component' @@ -22,6 +23,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { constructor ( private app: AppService, + private translate: TranslateService, ) { super() } @@ -29,7 +31,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise { let items: MenuItemOptions[] = [ { - label: 'Close', + label: this.translate.instant('Close'), click: () => { if (this.app.tabs.includes(tab)) { this.app.closeTab(tab, true) @@ -43,7 +45,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { items = [ ...items, { - label: 'Close other tabs', + label: this.translate.instant('Close other tabs'), click: () => { for (const t of this.app.tabs.filter(x => x !== tab)) { this.app.closeTab(t, true) @@ -51,7 +53,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { }, }, { - label: 'Close tabs to the right', + label: this.translate.instant('Close tabs to the right'), click: () => { for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) { this.app.closeTab(t, true) @@ -59,7 +61,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { }, }, { - label: 'Close tabs to the left', + label: this.translate.instant('Close tabs to the left'), click: () => { for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) { this.app.closeTab(t, true) @@ -71,13 +73,13 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { if (tab.parent instanceof SplitTabComponent) { const directions: SplitDirection[] = ['r', 'b', 'l', 't'] items.push({ - label: 'Split', + label: this.translate.instant('Split'), submenu: directions.map(dir => ({ label: { - r: 'Right', - b: 'Down', - l: 'Left', - t: 'Up', + r: this.translate.instant('Right'), + b: this.translate.instant('Down'), + l: this.translate.instant('Left'), + t: this.translate.instant('Up'), }[dir], click: () => { (tab.parent as SplitTabComponent).splitTab(tab, dir) @@ -99,6 +101,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { private app: AppService, private ngbModal: NgbModal, private splitLayoutProfilesService: SplitLayoutProfilesService, + private translate: TranslateService, ) { super() } @@ -109,18 +112,18 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { items = [ ...items, { - label: 'Rename', + label: this.translate.instant('Rename'), click: () => tabHeader.showRenameTabModal(), }, { - label: 'Duplicate', + label: this.translate.instant('Duplicate'), click: () => this.app.duplicateTab(tab), }, { - label: 'Color', + label: this.translate.instant('Color'), sublabel: TAB_COLORS.find(x => x.value === tab.color)?.name, submenu: TAB_COLORS.map(color => ({ - label: color.name, + label: this.translate.instant(color.name), type: 'radio', checked: tab.color === color.value, click: () => { @@ -132,10 +135,10 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) { items.push({ - label: 'Save layout as profile', + label: this.translate.instant('Save layout as profile'), click: async () => { const modal = this.ngbModal.open(PromptModalComponent) - modal.componentInstance.prompt = 'Profile name' + modal.componentInstance.prompt = this.translate.instant('Profile name') const name = (await modal.result)?.value if (!name) { return @@ -154,6 +157,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { export class TaskCompletionContextMenu extends TabContextMenuItemProvider { constructor ( private app: AppService, + private translate: TranslateService, ) { super() } @@ -167,10 +171,10 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { if (process) { items.push({ enabled: false, - label: 'Current process: ' + process.name, + label: this.translate.instant('Current process: {name}', process), }) items.push({ - label: 'Notify when done', + label: this.translate.instant('Notify when done'), type: 'checkbox', checked: extTab.__completionNotificationEnabled, click: () => { @@ -178,7 +182,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { if (extTab.__completionNotificationEnabled) { this.app.observeTabCompletion(tab).subscribe(() => { - new Notification('Process completed', { + new Notification(this.translate.instant('Process completed'), { body: process.name, }).addEventListener('click', () => { this.app.selectTab(tab) @@ -192,7 +196,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { }) } items.push({ - label: 'Notify on activity', + label: this.translate.instant('Notify on activity'), type: 'checkbox', checked: !!extTab.__outputNotificationSubscription, click: () => { @@ -204,7 +208,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { if (extTab.__outputNotificationSubscription && active) { extTab.__outputNotificationSubscription.unsubscribe() extTab.__outputNotificationSubscription = null - new Notification('Tab activity', { + new Notification(this.translate.instant('Tab activity'), { body: tab.title, }).addEventListener('click', () => { this.app.selectTab(tab) @@ -228,6 +232,7 @@ export class ProfilesContextMenu extends TabContextMenuItemProvider { private profilesService: ProfilesService, private tabsService: TabsService, private app: AppService, + private translate: TranslateService, hotkeys: HotkeysService, ) { super() @@ -270,7 +275,7 @@ export class ProfilesContextMenu extends TabContextMenuItemProvider { if (!tabHeader && tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) { return [ { - label: 'Switch profile', + label: this.translate.instant('Switch profile'), click: () => this.switchTabProfile(tab), }, ] diff --git a/tabby-core/src/theme.ts b/tabby-core/src/theme.ts index 1a5ff2bc..51340140 100644 --- a/tabby-core/src/theme.ts +++ b/tabby-core/src/theme.ts @@ -1,28 +1,41 @@ import { Injectable } from '@angular/core' +import { TranslateService } from '@ngx-translate/core' import { Theme } from './api' /** @hidden */ @Injectable() export class StandardTheme extends Theme { - name = 'Standard' + name = this.translate.instant('Standard') css = require('./theme.scss') terminalBackground = '#222a33' + + constructor (private translate: TranslateService) { + super() + } } /** @hidden */ @Injectable() export class StandardCompactTheme extends Theme { - name = 'Compact' + name = this.translate.instant('Compact') css = require('./theme.compact.scss') terminalBackground = '#222a33' macOSWindowButtonsInsetX = 8 macOSWindowButtonsInsetY = 6 + + constructor (private translate: TranslateService) { + super() + } } /** @hidden */ @Injectable() export class PaperTheme extends Theme { - name = 'Paper' + name = this.translate.instant('Paper') css = require('./theme.paper.scss') terminalBackground = '#f7f1e0' + + constructor (private translate: TranslateService) { + super() + } } diff --git a/tabby-core/src/utils.ts b/tabby-core/src/utils.ts index 082bc136..43562c35 100644 --- a/tabby-core/src/utils.ts +++ b/tabby-core/src/utils.ts @@ -1,5 +1,6 @@ import * as os from 'os' import { NgZone } from '@angular/core' +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' export const WIN_BUILD_CONPTY_SUPPORTED = 17692 export const WIN_BUILD_CONPTY_STABLE = 18309 @@ -56,13 +57,13 @@ export class ResettableTimeout { } export const TAB_COLORS = [ - { name: 'No color', value: null }, - { name: 'Blue', value: '#0275d8' }, - { name: 'Green', value: '#5cb85c' }, - { name: 'Orange', value: '#f0ad4e' }, - { name: 'Purple', value: '#613d7c' }, - { name: 'Red', value: '#d9534f' }, - { name: 'Yellow', value: '#ffd500' }, + { name: _('No color'), value: null }, + { name: _('Blue'), value: '#0275d8' }, + { name: _('Green'), value: '#5cb85c' }, + { name: _('Orange'), value: '#f0ad4e' }, + { name: _('Purple'), value: '#613d7c' }, + { name: _('Red'), value: '#d9534f' }, + { name: _('Yellow'), value: '#ffd500' }, ] export function serializeFunction Promise> (fn: T): T { diff --git a/tabby-core/yarn.lock b/tabby-core/yarn.lock index 35ebc673..89251ae3 100644 --- a/tabby-core/yarn.lock +++ b/tabby-core/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@ngx-translate/core@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-14.0.0.tgz#af421d0e1a28376843f0fed375cd2fae7630a5ff" + integrity sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w== + dependencies: + tslib "^2.3.0" + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -56,6 +63,37 @@ js-yaml@^4.0.0: dependencies: argparse "^2.0.1" +make-plural@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-4.3.0.tgz#f23de08efdb0cac2e0c9ba9f315b0dff6b4c2735" + integrity sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA== + optionalDependencies: + minimist "^1.2.0" + +messageformat-formatters@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz#0492c1402a48775f751c9b17c0354e92be012b08" + integrity sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg== + +messageformat-parser@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/messageformat-parser/-/messageformat-parser-4.1.3.tgz#b824787f57fcda7d50769f5b63e8d4fda68f5b9e" + integrity sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg== + +messageformat@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/messageformat/-/messageformat-2.3.0.tgz#de263c49029d5eae65d7ee25e0754f57f425ad91" + integrity sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w== + dependencies: + make-plural "^4.3.0" + messageformat-formatters "^2.0.1" + messageformat-parser "^4.1.2" + +minimist@^1.2.0: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + mixpanel@^0.13.0: version "0.13.0" resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.13.0.tgz#699bf510d9ba013c75edcf979ff1e24085fde9d2" @@ -85,6 +123,13 @@ ngx-perfect-scrollbar@^10.1.0: resize-observer-polyfill "^1.5.0" tslib "^2.0.0" +ngx-translate-messageformat-compiler@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.11.0.tgz#c9b71dd139ba5fcdcd809001e22622de589fd707" + integrity sha512-OdGfWV4fF3DhZqGIHcLmOnQDufugmZ+E90NYr1UPGRZgT10lilr9oLmIrisy3lW4THnZFNo9JXsX7+fX84LbDw== + dependencies: + tslib "^1.10.0" + perfect-scrollbar@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz#821d224ed8ff61990c23f26db63048cdc75b6b83" @@ -116,11 +161,21 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +tslib@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tslib@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" diff --git a/tabby-electron/src/hotkeys.ts b/tabby-electron/src/hotkeys.ts index 5d2e4789..3bcc05a5 100644 --- a/tabby-electron/src/hotkeys.ts +++ b/tabby-electron/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,14 +7,16 @@ export class ElectronHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'new-window', - name: 'New window', + name: this.translate.instant('New window'), }, { id: 'toggle-window', - name: 'Toggle terminal window', + name: this.translate.instant('Toggle terminal window'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index efa2c05c..8b19ff38 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -7,7 +7,7 @@ import { promisify } from 'util' import promiseIpc, { RendererProcessType } from 'electron-promise-ipc' import { execFile } from 'mz/child_process' import { Injectable, NgZone } from '@angular/core' -import { PlatformService, ClipboardContent, HostAppService, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileDownload, FileUploadOptions, wrapPromise } from 'tabby-core' +import { PlatformService, ClipboardContent, HostAppService, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileDownload, FileUploadOptions, wrapPromise, TranslateService } from 'tabby-core' import { ElectronService } from '../services/electron.service' import { ElectronHostWindow } from './hostWindow.service' import { ShellIntegrationService } from './shellIntegration.service' @@ -34,6 +34,7 @@ export class ElectronPlatformService extends PlatformService { private electron: ElectronService, private zone: NgZone, private shellIntegration: ShellIntegrationService, + private translate: TranslateService, ) { super() this.configPath = path.join(electron.app.getPath('userData'), 'config.yaml') @@ -204,7 +205,7 @@ export class ElectronPlatformService extends PlatformService { const result = await this.electron.dialog.showOpenDialog( this.hostWindow.getWindow(), { - buttonLabel: 'Select', + buttonLabel: this.translate.instant('Select'), properties, }, ) diff --git a/tabby-electron/src/services/updater.service.ts b/tabby-electron/src/services/updater.service.ts index d8f34a7c..8115e4e5 100644 --- a/tabby-electron/src/services/updater.service.ts +++ b/tabby-electron/src/services/updater.service.ts @@ -2,7 +2,7 @@ import type { AppUpdater } from 'electron-updater' import { Injectable } from '@angular/core' import axios from 'axios' -import { Logger, LogService, ConfigService, UpdaterService, PlatformService } from 'tabby-core' +import { Logger, LogService, ConfigService, UpdaterService, PlatformService, TranslateService } from 'tabby-core' import { ElectronService } from '../services/electron.service' const UPDATES_URL = 'https://api.github.com/repos/eugeny/tabby/releases/latest' @@ -18,6 +18,7 @@ export class ElectronUpdaterService extends UpdaterService { constructor ( log: LogService, config: ConfigService, + private translate: TranslateService, private platform: PlatformService, private electron: ElectronService, ) { @@ -132,8 +133,11 @@ export class ElectronUpdaterService extends UpdaterService { if ((await this.platform.showMessageBox( { type: 'warning', - message: 'Installing the update will close all tabs and restart Tabby.', - buttons: ['Update', 'Cancel'], + message: this.translate.instant('Installing the update will close all tabs and restart Tabby.'), + buttons: [ + this.translate.instant('Update'), + this.translate.instant('Cancel'), + ], defaultId: 0, cancelId: 1, } diff --git a/tabby-linkifier/src/decorator.ts b/tabby-linkifier/src/decorator.ts index 25abcf37..ffc6e520 100644 --- a/tabby-linkifier/src/decorator.ts +++ b/tabby-linkifier/src/decorator.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@angular/core' -import { ConfigService, PlatformService } from 'tabby-core' +import { ConfigService, PlatformService, TranslateService } from 'tabby-core' import { TerminalDecorator, BaseTerminalTabComponent } from 'tabby-terminal' import { LinkHandler } from './api' @@ -9,6 +9,7 @@ export class LinkHighlighterDecorator extends TerminalDecorator { constructor ( private config: ConfigService, private platform: PlatformService, + private translate: TranslateService, @Inject(LinkHandler) private handlers: LinkHandler[], ) { super() @@ -42,13 +43,13 @@ export class LinkHighlighterDecorator extends TerminalDecorator { this.platform.popupContextMenu([ { click: () => openLink(uri), - label: 'Open', + label: this.translate.instant('Open'), }, { click: async () => { this.platform.setClipboard({ text: await getLink(uri) }) }, - label: 'Copy', + label: this.translate.instant('Copy'), }, ]) return false diff --git a/tabby-local/src/buttonProvider.ts b/tabby-local/src/buttonProvider.ts index 68eff2b5..410cc63e 100644 --- a/tabby-local/src/buttonProvider.ts +++ b/tabby-local/src/buttonProvider.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Injectable } from '@angular/core' -import { ToolbarButtonProvider, ToolbarButton } from 'tabby-core' +import { ToolbarButtonProvider, ToolbarButton, TranslateService } from 'tabby-core' import { TerminalService } from './services/terminal.service' /** @hidden */ @@ -8,6 +8,7 @@ import { TerminalService } from './services/terminal.service' export class ButtonProvider extends ToolbarButtonProvider { constructor ( private terminal: TerminalService, + private translate: TranslateService, ) { super() } @@ -16,7 +17,7 @@ export class ButtonProvider extends ToolbarButtonProvider { return [ { icon: require('./icons/plus.svg'), - title: 'New terminal', + title: this.translate.instant('New terminal'), touchBarNSImage: 'NSTouchBarAddDetailTemplate', click: () => { this.terminal.openTab() diff --git a/tabby-local/src/components/commandLineEditor.component.pug b/tabby-local/src/components/commandLineEditor.component.pug index a5f70e68..1a8ef746 100644 --- a/tabby-local/src/components/commandLineEditor.component.pug +++ b/tabby-local/src/components/commandLineEditor.component.pug @@ -1,6 +1,6 @@ ng-container(*ngIf='!argvMode') .form-group - label Command line + label(translate) Command line .input-group .input-group-prepend a.input-group-text( @@ -16,7 +16,7 @@ ng-container(*ngIf='!argvMode') ng-container(*ngIf='argvMode') .form-group - label Program + label(translate) Program .input-group .input-group-prepend a.input-group-text( @@ -31,7 +31,7 @@ ng-container(*ngIf='argvMode') ) .form-group - label Arguments + label(translate) Arguments .input-group( *ngFor='let arg of _model.args; index as i; trackBy: trackByIndex', ) @@ -46,4 +46,4 @@ ng-container(*ngIf='argvMode') .mt-2 button.btn.btn-secondary((click)='_model.args.push("")') i.fas.fa-plus.mr-2 - | Add + span(translate) Add diff --git a/tabby-local/src/components/environmentEditor.component.pug b/tabby-local/src/components/environmentEditor.component.pug index 222c5462..ac247150 100644 --- a/tabby-local/src/components/environmentEditor.component.pug +++ b/tabby-local/src/components/environmentEditor.component.pug @@ -11,10 +11,10 @@ .d-flex button.btn.btn-secondary((click)='addEnvironmentVar()') i.fas.fa-plus.mr-2 - span Add + span(translate) Add .ml-auto - .text-muted Substitutions allowed. + .text-muted(translate) Substitutions allowed. .d-flex.ml-1(*ngIf='shouldShowExample()') - .text-muted Example: + .text-muted(translate) Example: a.ml-1((click)='addExample()', href='#') extend PATH diff --git a/tabby-local/src/components/localProfileSettings.component.pug b/tabby-local/src/components/localProfileSettings.component.pug index 9002eca5..00d5b23c 100644 --- a/tabby-local/src/components/localProfileSettings.component.pug +++ b/tabby-local/src/components/localProfileSettings.component.pug @@ -2,13 +2,13 @@ command-line-editor([model]='profile.options') .form-line(*ngIf='uac.isAvailable') .header - .title Run as administrator + .title(translate) Run as administrator toggle( [(ngModel)]='profile.options.runAsAdministrator', ) .form-group - label Working directory + label(translate) Working directory .input-group input.form-control( @@ -21,7 +21,7 @@ command-line-editor([model]='profile.options') i.fas.fa-folder-open .form-group - label Environment + label(translate) Environment environment-editor( type='text', [(model)]='profile.options.env', diff --git a/tabby-local/src/components/shellSettingsTab.component.pug b/tabby-local/src/components/shellSettingsTab.component.pug index 33ff7518..fd2da423 100644 --- a/tabby-local/src/components/shellSettingsTab.component.pug +++ b/tabby-local/src/components/shellSettingsTab.component.pug @@ -1,9 +1,9 @@ -h3.mb-3 Shell +h3.mb-3(translate) Shell .form-line(*ngIf='isConPTYAvailable') .header - .title Use ConPTY - .description Enables the experimental Windows ConPTY API + .title(translate) Use ConPTY + .description(translate) Enables the experimental Windows ConPTY API toggle( [(ngModel)]='config.store.terminal.useConPTY', @@ -11,7 +11,7 @@ h3.mb-3 Shell ) .alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.useConPTY && isConPTYAvailable && !isConPTYStable') - .mr-auto Windows 10 build 18309 or above is recommended for ConPTY + .mr-auto(translate) Windows 10 build 18309 or above is recommended for ConPTY .alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.profile.startsWith("WSL") && (!config.store.terminal.useConPTY)') - .mr-auto WSL terminal only supports TrueColor with ConPTY + .mr-auto(translate) WSL terminal only supports TrueColor with ConPTY diff --git a/tabby-local/src/components/terminalTab.component.ts b/tabby-local/src/components/terminalTab.component.ts index 1348979a..77f8505e 100644 --- a/tabby-local/src/components/terminalTab.component.ts +++ b/tabby-local/src/components/terminalTab.component.ts @@ -1,5 +1,5 @@ import { Component, Input, Injector } from '@angular/core' -import { BaseTabProcess, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild } from 'tabby-core' +import { BaseTabProcess, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild, TranslateService } from 'tabby-core' import { BaseTerminalTabComponent } from 'tabby-terminal' import { LocalProfile, SessionOptions } from '../api' import { Session } from '../session' @@ -20,6 +20,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent { // eslint-disable-next-line @typescript-eslint/no-useless-constructor constructor ( injector: Injector, + private translate: TranslateService, private uac: UACService, ) { super(injector) @@ -108,8 +109,14 @@ export class TerminalTabComponent extends BaseTerminalTabComponent { return (await this.platform.showMessageBox( { type: 'warning', - message: `"${children[0].command}" is still running. Close?`, - buttons: ['Kill', 'Cancel'], + message: this.translate.instant( + '"{command}" is still running. Close?', + children[0], + ), + buttons: [ + this.translate.instant('Kill'), + this.translate.instant('Cancel'), + ], defaultId: 0, cancelId: 1, } diff --git a/tabby-local/src/hotkeys.ts b/tabby-local/src/hotkeys.ts index a5534647..08193e40 100644 --- a/tabby-local/src/hotkeys.ts +++ b/tabby-local/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,10 +7,12 @@ export class LocalTerminalHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'new-tab', - name: 'New tab', + name: this.translate.instant('New tab'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-local/src/profiles.ts b/tabby-local/src/profiles.ts index 99e51f50..de8625b0 100644 --- a/tabby-local/src/profiles.ts +++ b/tabby-local/src/profiles.ts @@ -1,6 +1,6 @@ import deepClone from 'clone-deep' import { Injectable, Inject } from '@angular/core' -import { ProfileProvider, NewTabParameters, ConfigService, SplitTabComponent, AppService, PartialProfile } from 'tabby-core' +import { ProfileProvider, NewTabParameters, ConfigService, SplitTabComponent, AppService, PartialProfile, TranslateService } from 'tabby-core' import { TerminalTabComponent } from './components/terminalTab.component' import { LocalProfileSettingsComponent } from './components/localProfileSettings.component' import { ShellProvider, Shell, SessionOptions, LocalProfile } from './api' @@ -8,7 +8,7 @@ import { ShellProvider, Shell, SessionOptions, LocalProfile } from './api' @Injectable({ providedIn: 'root' }) export class LocalProfilesService extends ProfileProvider { id = 'local' - name = 'Local' + name = this.translate.instant('Local terminal') settingsComponent = LocalProfileSettingsComponent configDefaults = { options: { @@ -29,6 +29,7 @@ export class LocalProfilesService extends ProfileProvider { constructor ( private app: AppService, private config: ConfigService, + private translate: TranslateService, @Inject(ShellProvider) private shellProviders: ShellProvider[], ) { super() diff --git a/tabby-local/src/services/dockMenu.service.ts b/tabby-local/src/services/dockMenu.service.ts index 2845b43b..3e07cfa9 100644 --- a/tabby-local/src/services/dockMenu.service.ts +++ b/tabby-local/src/services/dockMenu.service.ts @@ -1,5 +1,5 @@ import { NgZone, Injectable } from '@angular/core' -import { ConfigService, HostAppService, Platform, ProfilesService } from 'tabby-core' +import { ConfigService, HostAppService, Platform, ProfilesService, TranslateService } from 'tabby-core' import { ElectronService } from 'tabby-electron' /** @hidden */ @@ -13,6 +13,7 @@ export class DockMenuService { private hostApp: HostAppService, private zone: NgZone, private profilesService: ProfilesService, + private translate: TranslateService, ) { config.changed$.subscribe(() => this.update()) } @@ -21,7 +22,7 @@ export class DockMenuService { if (this.hostApp.platform === Platform.Windows) { this.electron.app.setJumpList(this.config.store.profiles.length ? [{ type: 'custom', - name: 'Profiles', + name: this.translate.instant('Profiles'), items: this.config.store.profiles.map(profile => ({ type: 'task', program: process.execPath, diff --git a/tabby-local/src/shells/linuxDefault.ts b/tabby-local/src/shells/linuxDefault.ts index 68119328..996fd497 100644 --- a/tabby-local/src/shells/linuxDefault.ts +++ b/tabby-local/src/shells/linuxDefault.ts @@ -1,6 +1,6 @@ import * as fs from 'mz/fs' import { Injectable } from '@angular/core' -import { HostAppService, Platform, LogService, Logger } from 'tabby-core' +import { HostAppService, Platform, LogService, Logger, TranslateService } from 'tabby-core' import { ShellProvider, Shell } from '../api' @@ -11,6 +11,7 @@ export class LinuxDefaultShellProvider extends ShellProvider { constructor ( private hostApp: HostAppService, + private translate: TranslateService, log: LogService, ) { super() @@ -27,14 +28,14 @@ export class LinuxDefaultShellProvider extends ShellProvider { this.logger.warn('Could not detect user shell') return [{ id: 'default', - name: 'User default', + name: this.translate.instant('User default'), command: '/bin/sh', env: {}, }] } else { return [{ id: 'default', - name: 'User default', + name: this.translate.instant('User default'), command: line.split(':')[6], args: ['--login'], hidden: true, diff --git a/tabby-local/src/shells/macDefault.ts b/tabby-local/src/shells/macDefault.ts index 4393087b..e4f4e8e9 100644 --- a/tabby-local/src/shells/macDefault.ts +++ b/tabby-local/src/shells/macDefault.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import promiseIpc, { RendererProcessType } from 'electron-promise-ipc' -import { HostAppService, Platform } from 'tabby-core' +import { HostAppService, Platform, TranslateService } from 'tabby-core' import { ShellProvider, Shell } from '../api' @@ -11,6 +11,7 @@ export class MacOSDefaultShellProvider extends ShellProvider { constructor ( private hostApp: HostAppService, + private translate: TranslateService, ) { super() } @@ -21,7 +22,7 @@ export class MacOSDefaultShellProvider extends ShellProvider { } return [{ id: 'default', - name: 'OS default', + name: this.translate.instant('OS default'), command: await this.getDefaultShellCached(), args: ['--login'], hidden: true, diff --git a/tabby-local/src/shells/winDefault.ts b/tabby-local/src/shells/winDefault.ts index 79887285..0d26e047 100644 --- a/tabby-local/src/shells/winDefault.ts +++ b/tabby-local/src/shells/winDefault.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HostAppService, Platform } from 'tabby-core' +import { HostAppService, Platform, TranslateService } from 'tabby-core' import { ShellProvider, Shell } from '../api' @@ -17,6 +17,7 @@ export class WindowsDefaultShellProvider extends ShellProvider { wsl: WSLShellProvider, stock: WindowsStockShellsProvider, private hostApp: HostAppService, + private translate: TranslateService, ) { super() this.providers = [ @@ -39,7 +40,7 @@ export class WindowsDefaultShellProvider extends ShellProvider { return [{ ...shell, id: 'default', - name: `OS default (${shell.name})`, + name: this.translate.instant('OS default ({name})', shell), hidden: true, env: {}, }] diff --git a/tabby-local/src/tabContextMenu.ts b/tabby-local/src/tabContextMenu.ts index 57577ced..d935fd41 100644 --- a/tabby-local/src/tabContextMenu.ts +++ b/tabby-local/src/tabContextMenu.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, SplitTabComponent, NotificationsService, MenuItemOptions, ProfilesService, PromptModalComponent } from 'tabby-core' +import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, SplitTabComponent, NotificationsService, MenuItemOptions, ProfilesService, PromptModalComponent, TranslateService } from 'tabby-core' import { TerminalTabComponent } from './components/terminalTab.component' import { UACService } from './services/uac.service' import { TerminalService } from './services/terminal.service' @@ -13,6 +13,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { private config: ConfigService, private ngbModal: NgbModal, private notifications: NotificationsService, + private translate: TranslateService, ) { super() } @@ -23,10 +24,10 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { } const items: MenuItemOptions[] = [ { - label: 'Save as profile', + label: this.translate.instant('Save as profile'), click: async () => { const modal = this.ngbModal.open(PromptModalComponent) - modal.componentInstance.prompt = 'New profile name' + modal.componentInstance.prompt = this.translate.instant('New profile name') const name = (await modal.result)?.value if (!name) { return @@ -44,7 +45,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { profile, ] this.config.save() - this.notifications.info('Saved') + this.notifications.info(this.translate.instant('Saved')) }, }, ] @@ -63,6 +64,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { private profilesService: ProfilesService, private terminalService: TerminalService, private uac: UACService, + private translate: TranslateService, ) { super() } @@ -72,7 +74,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { const items: MenuItemOptions[] = [ { - label: 'New terminal', + label: this.translate.instant('New terminal'), click: () => { if (tab instanceof TerminalTabComponent) { this.profilesService.openNewTabForProfile(tab.profile) @@ -82,7 +84,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { }, }, { - label: 'New with profile', + label: this.translate.instant('New with profile'), submenu: profiles.map(profile => ({ label: profile.name, click: async () => { @@ -98,7 +100,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { if (this.uac.isAvailable) { items.push({ - label: 'New admin tab', + label: this.translate.instant('New admin tab'), submenu: profiles.map(profile => ({ label: profile.name, click: () => { @@ -116,7 +118,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { if (tab instanceof TerminalTabComponent && tabHeader && this.uac.isAvailable) { items.push({ - label: 'Duplicate as administrator', + label: this.translate.instant('Duplicate as administrator'), click: () => { this.profilesService.openNewTabForProfile({ ...tab.profile, @@ -131,7 +133,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { if (tab instanceof TerminalTabComponent && tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) { items.push({ - label: 'Focus all panes', + label: this.translate.instant('Focus all panes'), click: () => { tab.focusAllPanes() }, diff --git a/tabby-plugin-manager/src/components/pluginsSettingsTab.component.pug b/tabby-plugin-manager/src/components/pluginsSettingsTab.component.pug index 8332a340..da6795b6 100644 --- a/tabby-plugin-manager/src/components/pluginsSettingsTab.component.pug +++ b/tabby-plugin-manager/src/components/pluginsSettingsTab.component.pug @@ -1,16 +1,16 @@ .d-flex.mb-3 - h3 Plugins + h3(translate) Plugins button.btn.btn-secondary.btn-sm.ml-auto((click)='openPluginsFolder()') i.fas.fa-folder - span Plugins folder + span(translate) Plugins folder .alert.alert-danger(*ngIf='errorMessage') - strong Error in {{erroredPlugin}}: + strong(translate, [translateParams]='{plugin: erroredPlugin}') Error in {plugin}: pre {{errorMessage}} ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) Available + a(ngbNavLink, translate) Available ng-template(ngbNavContent) .input-group.mb-3.mt-3 .input-group-prepend @@ -40,14 +40,14 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') ) i.fas.fa-fw.fa-cloud-download(*ngIf='busy.get(plugin.name) != BusyState.Installing') i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing') - span.ml-2 Get + span.ml-2(translate) Get button.btn.btn-secondary.btn-block.justify-content-center( *ngIf='plugin.homepage', (click)='showPluginHomepage(plugin)' ) i.fas.fa-fw.fa-external-link-alt - span.ml-2 Homepage + span.ml-2(translate) Homepage .col-8 ng-container(*ngTemplateOutlet='pluginInfo; context: { plugin }') @@ -55,7 +55,7 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') .mt-2 {{plugin.description}} li(ngbNavItem) - a(ngbNavLink) Installed + a(ngbNavLink, translate) Installed ng-template(ngbNavContent) ngb-accordion.mb-4([closeOthers]='true') ng-container(*ngFor='let plugin of pluginManager.installedPlugins') @@ -64,8 +64,8 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') .text-left.mr-auto div strong {{plugin.name}} - small.text-muted.ml-2(*ngIf='plugin.isBuiltin') Built-in - small.text-warning.ml-2(*ngIf='!isPluginEnabled(plugin)') Disabled + small.text-muted.ml-2(*ngIf='plugin.isBuiltin', translate) Built-in + small.text-warning.ml-2(*ngIf='!isPluginEnabled(plugin)', translate) Disabled small.d-block.text-muted {{plugin.description}} button.btn.btn-primary.ml-2( @@ -75,7 +75,7 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') ) i.fas.fa-fw.fa-arrow-up(*ngIf='busy.get(plugin.name) != BusyState.Installing') i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing') - span Upgrade to {{knownUpgrades[plugin.name].version}} + span(translate, [translateParams]='{version: knownUpgrades[plugin.name].version}') Upgrade to {version} ng-template(ngbPanelContent) .row @@ -83,12 +83,14 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') button.btn.btn-warning.btn-block.justify-content-center( (click)='togglePlugin(plugin)', *ngIf='isPluginEnabled(plugin)', - [disabled]='!canDisablePlugin(plugin)' + [disabled]='!canDisablePlugin(plugin)', + translate ) Disable button.btn.btn-success.btn-block.justify-content-center( (click)='togglePlugin(plugin)', - *ngIf='canDisablePlugin(plugin) && !isPluginEnabled(plugin)' + *ngIf='canDisablePlugin(plugin) && !isPluginEnabled(plugin)', + translate ) Enable button.btn.btn-danger.btn-block.justify-content-center( @@ -98,26 +100,25 @@ ul.nav-tabs.mb-2(ngbNav, #nav='ngbNav') ) i.fas.fa-fw.fa-trash(*ngIf='busy.get(plugin.name) != BusyState.Uninstalling') i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Uninstalling') - span Uninstall + span(translate) Uninstall .col-8 ng-container(*ngTemplateOutlet='pluginInfo; context: { plugin }') - .mt-2 {{plugin.description}} ng-template(#pluginInfo, let-plugin='plugin') .row.align-items-center .col-4 - strong Version + strong(translate) Version .col-8 span {{plugin.version}} .row.align-items-center .col-4 - strong Author + strong(translate) Author .col-8 .badge.badge-success(*ngIf='plugin.isOfficial') i.fas.fa-check - span.ml-1 Official + span.ml-1(translate) Official a.btn.btn-link.px-0.w-auto((click)='showPluginInfo(plugin)', *ngIf='!plugin.isOfficial') span {{plugin.author}} i.fas.fa-fw.fa-external-link-alt.ml-2 diff --git a/tabby-serial/src/components/serialProfileSettings.component.pug b/tabby-serial/src/components/serialProfileSettings.component.pug index 72e38d54..11e351bf 100644 --- a/tabby-serial/src/components/serialProfileSettings.component.pug +++ b/tabby-serial/src/components/serialProfileSettings.component.pug @@ -1,11 +1,11 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) General + a(ngbNavLink, translate) General ng-template(ngbNavContent) .row .col-6(ng:if='hostApp.platform !== Platform.Web') .form-group - label Device + label(translate) Device input.form-control( type='text', alwaysVisibleTypeahead, @@ -16,7 +16,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .col-6 .form-group - label Baud Rate + label(translate) Baud rate input.form-control( type='number', alwaysVisibleTypeahead, @@ -28,11 +28,11 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') stream-processing-settings([options]='profile.options') li(ngbNavItem) - a(ngbNavLink) Advanced + a(ngbNavLink, translate) Advanced ng-template(ngbNavContent) .form-line .header - .title Data bits + .title(translate) Data bits input.form-control( type='number', placeholder='8', @@ -41,7 +41,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Stop bits + .title(translate) Stop bits input.form-control( type='number', placeholder='1', @@ -50,12 +50,12 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Parity + .title(translate) Parity select.form-control( type='text', [(ngModel)]='profile.options.parity' ) - option(value='none') None + option(value='none', translate) None option(value='even') Even option(value='odd') Odd option(value='mark', ng:if='hostApp.platform === Platform.Windows') Mark @@ -83,12 +83,12 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Slow feed - .description Sends data one byte at a time + .title(translate) Slow feed + .description(translate) Sends data one byte at a time toggle([(ngModel)]='profile.options.slowFeed') li(ngbNavItem) - a(ngbNavLink) Login scripts + a(ngbNavLink, translate) Login scripts ng-template(ngbNavContent) login-scripts-settings([options]='profile.options') diff --git a/tabby-serial/src/components/serialTab.component.pug b/tabby-serial/src/components/serialTab.component.pug index 274d25fa..7da72f6e 100644 --- a/tabby-serial/src/components/serialTab.component.pug +++ b/tabby-serial/src/components/serialTab.component.pug @@ -9,8 +9,8 @@ .mr-auto button.btn.btn-sm.btn-link.mr-3((click)='changeBaudRate()', *ngIf='session && session.open && hostApp.platform !== Platform.Web') - span Change baud rate + span(translate) Change baud rate button.btn.btn-sm.btn-link((click)='reconnect()', *ngIf='!session || !session.open') i.fas.fa-redo - span Reconnect + span(translate) Reconnect diff --git a/tabby-serial/src/components/serialTab.component.ts b/tabby-serial/src/components/serialTab.component.ts index e49ba7a0..043ffc09 100644 --- a/tabby-serial/src/components/serialTab.component.ts +++ b/tabby-serial/src/components/serialTab.component.ts @@ -2,7 +2,7 @@ import colors from 'ansi-colors' import { Component, Injector } from '@angular/core' import { first } from 'rxjs' -import { Platform, SelectorService } from 'tabby-core' +import { Platform, SelectorService, TranslateService } from 'tabby-core' import { BaseTerminalTabComponent } from 'tabby-terminal' import { SerialSession, BAUD_RATES, SerialProfile } from '../api' @@ -23,6 +23,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { constructor ( injector: Injector, private selector: SelectorService, + private translate: TranslateService, ) { super(injector) this.enableToolbar = true @@ -67,14 +68,13 @@ export class SerialTabComponent extends BaseTerminalTabComponent { const session = new SerialSession(this.injector, this.profile) this.setSession(session) - this.write(`Connecting to `) - this.startSpinner('Connecting') + this.startSpinner(this.translate.instant('Connecting')) try { await this.session!.start() this.stopSpinner() - session.emitServiceMessage('Port opened') + session.emitServiceMessage(this.translate.instant('Port opened')) } catch (e) { this.stopSpinner() this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n') @@ -89,7 +89,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { this.session?.resize(this.size.columns, this.size.rows) }) this.attachSessionHandler(this.session!.destroyed$, () => { - this.write('Press any key to reconnect\r\n') + this.write(this.translate.instant('Press any key to reconnect') + '\r\n') this.input$.pipe(first()).subscribe(() => { if (!this.session?.open) { this.reconnect() @@ -114,9 +114,12 @@ export class SerialTabComponent extends BaseTerminalTabComponent { } async changeBaudRate () { - const rate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({ - name: x.toString(), result: x, - }))) + const rate = await this.selector.show( + this.translate.instant('Baud rate'), + BAUD_RATES.map(x => ({ + name: x.toString(), result: x, + })), + ) this.serialPort.update({ baudRate: rate }) this.profile!.options.baudrate = rate } diff --git a/tabby-serial/src/hotkeys.ts b/tabby-serial/src/hotkeys.ts index b0ab3a0d..98fdf342 100644 --- a/tabby-serial/src/hotkeys.ts +++ b/tabby-serial/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,14 +7,16 @@ export class SerialHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'serial', - name: 'Show Serial connections', + name: this.translate.instant('Show Serial connections'), }, { id: 'restart-serial-session', - name: 'Restart current serial session', + name: this.translate.instant('Restart current serial session'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-serial/src/profiles.ts b/tabby-serial/src/profiles.ts index d32e1d53..55047c4e 100644 --- a/tabby-serial/src/profiles.ts +++ b/tabby-serial/src/profiles.ts @@ -3,7 +3,7 @@ import SerialPort from 'serialport' import WSABinding from 'serialport-binding-webserialapi' import deepClone from 'clone-deep' import { Injectable } from '@angular/core' -import { ProfileProvider, NewTabParameters, SelectorService, HostAppService, Platform } from 'tabby-core' +import { ProfileProvider, NewTabParameters, SelectorService, HostAppService, Platform, TranslateService } from 'tabby-core' import { SerialProfileSettingsComponent } from './components/serialProfileSettings.component' import { SerialTabComponent } from './components/serialTab.component' import { SerialService } from './services/serial.service' @@ -12,7 +12,7 @@ import { BAUD_RATES, SerialProfile } from './api' @Injectable({ providedIn: 'root' }) export class SerialProfilesService extends ProfileProvider { id = 'serial' - name = 'Serial' + name = this.translate.instant('Serial') settingsComponent = SerialProfileSettingsComponent configDefaults = { options: { @@ -38,6 +38,7 @@ export class SerialProfilesService extends ProfileProvider { private selector: SelectorService, private serial: SerialService, private hostApp: HostAppService, + private translate: TranslateService, ) { super() if (hostApp.platform === Platform.Web) { @@ -51,7 +52,7 @@ export class SerialProfilesService extends ProfileProvider { { id: `serial:web`, type: 'serial', - name: 'Serial connection', + name: this.translate.instant('Serial connection'), icon: 'fas fa-microchip', isBuiltin: true, } as SerialProfile, @@ -62,7 +63,7 @@ export class SerialProfilesService extends ProfileProvider { { id: `serial:template`, type: 'serial', - name: 'Serial connection', + name: this.translate.instant('Serial connection'), icon: 'fas fa-microchip', isBuiltin: true, isTemplate: true, @@ -70,7 +71,9 @@ export class SerialProfilesService extends ProfileProvider { ...(await this.serial.listPorts()).map(p => ({ id: `serial:port-${slugify(p.name).replace('.', '-')}`, type: 'serial', - name: p.description ? `Serial: ${p.description}` : 'Serial', + name: p.description ? + this.translate.instant('Serial: {description}', p) : + this.translate.instant('Serial'), icon: 'fas fa-microchip', isBuiltin: true, options: { @@ -83,9 +86,12 @@ export class SerialProfilesService extends ProfileProvider { async getNewTabParameters (profile: SerialProfile): Promise> { if (!profile.options.baudrate) { profile = deepClone(profile) - profile.options.baudrate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({ - name: x.toString(), result: x, - }))) + profile.options.baudrate = await this.selector.show( + this.translate.instant('Baud rate'), + BAUD_RATES.map(x => ({ + name: x.toString(), result: x, + })), + ) } return { type: SerialTabComponent, diff --git a/tabby-settings/src/buttonProvider.ts b/tabby-settings/src/buttonProvider.ts index 9d342c73..243ddd8c 100644 --- a/tabby-settings/src/buttonProvider.ts +++ b/tabby-settings/src/buttonProvider.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { ToolbarButtonProvider, ToolbarButton, AppService, HostAppService, HotkeysService } from 'tabby-core' +import { ToolbarButtonProvider, ToolbarButton, AppService, HostAppService, HotkeysService, TranslateService } from 'tabby-core' import { SettingsTabComponent } from './components/settingsTab.component' @@ -10,6 +10,7 @@ export class ButtonProvider extends ToolbarButtonProvider { hostApp: HostAppService, hotkeys: HotkeysService, private app: AppService, + private translate: TranslateService, ) { super() hostApp.settingsUIRequest$.subscribe(() => this.open()) @@ -24,7 +25,7 @@ export class ButtonProvider extends ToolbarButtonProvider { provide (): ToolbarButton[] { return [{ icon: require('./icons/cog.svg'), - title: 'Settings', + title: this.translate.instant('Settings'), touchBarNSImage: 'NSTouchBarComposeTemplate', weight: 10, click: (): void => this.open(), diff --git a/tabby-settings/src/components/configSyncSettingsTab.component.pug b/tabby-settings/src/components/configSyncSettingsTab.component.pug index 7a196322..d1c6a8af 100644 --- a/tabby-settings/src/components/configSyncSettingsTab.component.pug +++ b/tabby-settings/src/components/configSyncSettingsTab.component.pug @@ -1,12 +1,12 @@ -h3.mb-3 Config sync +h3.mb-3(translate) Config sync ul.nav-tabs(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) Sync + a(ngbNavLink, translate) Sync ng-template(ngbNavContent) .form-line .header - .title Sync host + .title(translate) Sync host .input-group.w-50 input.form-control( @@ -20,8 +20,8 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Secret sync token - .description Get it from the Tabby Web settings window + .title(translate) Secret sync token + .description(translate) Get it from the Tabby Web settings window .input-group input.form-control( @@ -38,16 +38,16 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ng-container(*ngIf='config.store.configSync.token') .alert.alert-danger(*ngIf='connectionSuccessful === false') i.fas.fa-exclamation-triangle - span.ml-2 Connection failed: {{connectionError}} + span.ml-2(translate, [translateParams]='{error: connectionError}') Connection failed: {error} ng-container(*ngIf='connectionSuccessful') .form-line .header - .title Configs + .title(translate) Configs div(*ngIf='configs === null') i.fas.fa-fw.fa-circle-notch.fa-spin - span.ml-2 Loading configs... + span.ml-2(translate) Loading configs... ng-container(*ngIf='configs !== null') .list-group-light @@ -59,34 +59,34 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') i.fas.fa-fw.fa-file .ml-2.d-flex.flex-column.align-items-start div {{cfg.name}} - small.text-muted Modified on {{cfg.modified_at|date:'medium'}} + small.text-muted(translate, [translateParams]='{date: cfg.modified_at|date:"medium"}') Modified on {date} .mr-auto button.btn.btn-link.ml-1( (click)='uploadAndSync(cfg)', [class.hover-reveal]='!isActiveConfig(cfg)' ) i.fas.fa-arrow-up - span.ml-2(*ngIf='isActiveConfig(cfg)') Upload - span.ml-2(*ngIf='!isActiveConfig(cfg)') Replace + span.ml-2(*ngIf='isActiveConfig(cfg)', translate) Upload + span.ml-2(*ngIf='!isActiveConfig(cfg)', translate) Replace button.btn.btn-link.ml-1( (click)='downloadAndSync(cfg)', [class.hover-reveal]='!isActiveConfig(cfg)' ) i.fas.fa-arrow-down - span.ml-2 Download + span.ml-2(translate) Download a.list-group-item.list-group-item-action.d-flex.align-items-center( href='#', (click)='uploadAsNew()' ) i.fas.fa-fw i.fas.fa-fw.fa-cloud-upload-alt - .ml-2 Upload as a new config + .ml-2(translate) Upload as a new config ng-container(*ngIf='hasMatchingRemoteConfig()') .form-line .header - .title Sync automatically - .description Automatically upload changes and check for updates every minute + .title(translate) Sync automatically + .description(translate) Automatically upload changes and check for updates every minute toggle( [(ngModel)]='config.store.configSync.auto', @@ -94,11 +94,11 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) li(ngbNavItem) - a(ngbNavLink) Advanced + a(ngbNavLink, translate) Advanced ng-template(ngbNavContent) .form-line .header - .title Sync hotkeys + .title(translate) Sync hotkeys toggle( [(ngModel)]='config.store.configSync.parts.hotkeys', (ngModelChange)='config.save()', @@ -106,7 +106,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Sync window settings + .title(translate) Sync window settings toggle( [(ngModel)]='config.store.configSync.parts.appearance', (ngModelChange)='config.save()', @@ -114,7 +114,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Sync Vault + .title(translate) Sync Vault toggle( [(ngModel)]='config.store.configSync.parts.vault', (ngModelChange)='config.save()', diff --git a/tabby-settings/src/components/configSyncSettingsTab.component.ts b/tabby-settings/src/components/configSyncSettingsTab.component.ts index 1d0a186b..912628ba 100644 --- a/tabby-settings/src/components/configSyncSettingsTab.component.ts +++ b/tabby-settings/src/components/configSyncSettingsTab.component.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Component, HostBinding } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { BaseComponent, ConfigService, PromptModalComponent, HostAppService, PlatformService, NotificationsService } from 'tabby-core' +import { BaseComponent, ConfigService, PromptModalComponent, HostAppService, PlatformService, NotificationsService, TranslateService } from 'tabby-core' import { Config, ConfigSyncService } from '../services/configSync.service' @@ -24,6 +24,7 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent { private hostApp: HostAppService, private ngbModal: NgbModal, private notifications: NotificationsService, + private translate: TranslateService, ) { super() } @@ -54,9 +55,9 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent { } async uploadAsNew () { - let name = `New config on ${this.hostApp.platform}` + let name = this.translate.instant('New config on {platform}', this.hostApp) const modal = this.ngbModal.open(PromptModalComponent) - modal.componentInstance.prompt = 'Name for the new config' + modal.componentInstance.prompt = this.translate.instant('Name for the new config') modal.componentInstance.value = name name = (await modal.result)?.value if (!name) { @@ -72,8 +73,11 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent { if (this.config.store.configSync.configID !== cfg.id) { if ((await this.platform.showMessageBox({ type: 'warning', - message: 'Overwrite the config on the remote side and start syncing?', - buttons: ['Overwrite remote and sync', 'Cancel'], + message: this.translate.instant('Overwrite the config on the remote side and start syncing?'), + buttons: [ + this.translate.instant('Overwrite remote and sync'), + this.translate.instant('Cancel'), + ], defaultId: 1, cancelId: 1, })).response === 1) { @@ -83,14 +87,17 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent { this.configSync.setConfig(cfg) await this.configSync.upload() this.loadConfigs() - this.notifications.info('Config uploaded') + this.notifications.info(this.translate.instant('Config uploaded')) } async downloadAndSync (cfg: Config) { if ((await this.platform.showMessageBox({ type: 'warning', - message: 'Overwrite the local config and start syncing?', - buttons: ['Overwrite local and sync', 'Cancel'], + message: this.translate.instant('Overwrite the local config and start syncing?'), + buttons: [ + this.translate.instant('Overwrite local and sync'), + this.translate.instant('Cancel'), + ], defaultId: 1, cancelId: 1, })).response === 1) { @@ -98,7 +105,7 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent { } this.configSync.setConfig(cfg) await this.configSync.download() - this.notifications.info('Config downloaded') + this.notifications.info(this.translate.instant('Config downloaded')) } hasMatchingRemoteConfig () { diff --git a/tabby-settings/src/components/editProfileModal.component.pug b/tabby-settings/src/components/editProfileModal.component.pug index eef3168f..99e4cfdf 100644 --- a/tabby-settings/src/components/editProfileModal.component.pug +++ b/tabby-settings/src/components/editProfileModal.component.pug @@ -2,13 +2,13 @@ h3.m-0 {{profile.name}} .modal-header(*ngIf='defaultsMode') - h3.m-0 Defaults for {{profileProvider.name}} + h3.m-0(translate, [translateParams]='{type: profileProvider.name}') Defaults for {type} .modal-body .row .col-12.col-lg-4 .form-group(*ngIf='!defaultsMode') - label Name + label(translate) Name input.form-control( type='text', autofocus, @@ -16,7 +16,7 @@ ) .form-group(*ngIf='!defaultsMode') - label Group + label(translate) Group input.form-control( type='text', alwaysVisibleTypeahead, @@ -26,7 +26,7 @@ ) .form-group(*ngIf='!defaultsMode') - label Icon + label(translate) Icon .input-group input.form-control( type='text', @@ -45,7 +45,7 @@ .form-line .header - .title Color + .title(translate) Color input.form-control.w-50( type='text', [(ngModel)]='profile.color', @@ -56,8 +56,8 @@ .form-line .header - .title Disable dynamic tab title - .description Connection name will be used instead + .title(translate) Disable dynamic tab title + .description(translate) Connection name will be used instead toggle([(ngModel)]='profile.disableDynamicTitle') .mb-4 @@ -66,5 +66,5 @@ ng-template(#placeholder) .modal-footer - button.btn.btn-primary((click)='save()') Save - button.btn.btn-danger((click)='cancel()') Cancel + button.btn.btn-primary((click)='save()', translate) Save + button.btn.btn-danger((click)='cancel()', translate) Cancel diff --git a/tabby-settings/src/components/hotkeyInputModal.component.pug b/tabby-settings/src/components/hotkeyInputModal.component.pug index 6c28b4db..da7c74f1 100644 --- a/tabby-settings/src/components/hotkeyInputModal.component.pug +++ b/tabby-settings/src/components/hotkeyInputModal.component.pug @@ -1,5 +1,5 @@ .modal-header - h5 Press the key now + h5(translate) Press the key now .modal-body .input @@ -9,4 +9,4 @@ div([style.width]='timeoutProgress + "%"') .modal-footer - button.btn.btn-primary((click)='close()') Cancel + button.btn.btn-primary((click)='close()', translate) Cancel diff --git a/tabby-settings/src/components/hotkeySettingsTab.component.pug b/tabby-settings/src/components/hotkeySettingsTab.component.pug index 0f9f2469..82601959 100644 --- a/tabby-settings/src/components/hotkeySettingsTab.component.pug +++ b/tabby-settings/src/components/hotkeySettingsTab.component.pug @@ -1,4 +1,4 @@ -h3.mb-3 Hotkeys +h3.mb-3(translate) Hotkeys .input-group.mb-4 .input-group-prepend diff --git a/tabby-settings/src/components/multiHotkeyInput.component.pug b/tabby-settings/src/components/multiHotkeyInput.component.pug index 9d4af73c..9591f207 100644 --- a/tabby-settings/src/components/multiHotkeyInput.component.pug +++ b/tabby-settings/src/components/multiHotkeyInput.component.pug @@ -3,4 +3,4 @@ .stroke(*ngFor='let stroke of item') {{stroke}} .remove((click)='removeItem(item)') × -.add((click)='addItem()') Add... +.add((click)='addItem()', translate) Add... diff --git a/tabby-settings/src/components/profilesSettingsTab.component.pug b/tabby-settings/src/components/profilesSettingsTab.component.pug index 68009192..583c6121 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.pug +++ b/tabby-settings/src/components/profilesSettingsTab.component.pug @@ -1,12 +1,12 @@ -h3.mb-3 Profiles +h3.mb-3(translate) Profiles ul.nav-tabs(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) Profiles + a(ngbNavLink, translate) Profiles ng-template(ngbNavContent) .form-line .header - .title Default profile for new tabs + .title(translate) Default profile for new tabs select.form-control( [(ngModel)]='config.store.terminal.profile', @@ -30,7 +30,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') button.btn.btn-primary.flex-shrink-0.ml-3((click)='newProfile()') i.fas.fa-fw.fa-plus - | New profile + span(translate) New profile .list-group.mt-3.mb-3 ng-container(*ngFor='let group of profileGroups') @@ -40,7 +40,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) .fa.fa-fw.fa-chevron-right(*ngIf='group.collapsed') .fa.fa-fw.fa-chevron-down(*ngIf='!group.collapsed') - span.ml-3.mr-auto {{group.name || "Ungrouped"}} + span.ml-3.mr-auto {{group.name || ("Ungrouped"|translate)}} button.btn.btn-sm.btn-link.hover-reveal.ml-2( *ngIf='group.editable && group.name', (click)='$event.stopPropagation(); editGroup(group)' @@ -88,12 +88,12 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .ml-1(class='badge badge-{{getTypeColorClass(profile)}}') {{getTypeLabel(profile)}} li(ngbNavItem) - a(ngbNavLink) Advanced + a(ngbNavLink, translate) Advanced ng-template(ngbNavContent) .form-line(*ngIf='config.store.profiles.length > 0') .header - .title Show recent profiles in selector - .description Set to 0 to disable recent profiles + .title(translate) Show recent profiles in selector + .description(translate) Set to 0 to disable recent profiles input.form-control( type='number', @@ -105,8 +105,8 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line(*ngIf='config.store.profiles.length > 0') .header - .title Show built-in profiles in selector - .description If disabled, only custom profiles will show up in the profile selector + .title(translate) Show built-in profiles in selector + .description(translate) If disabled, only custom profiles will show up in the profile selector toggle( [(ngModel)]='config.store.terminal.showBuiltinProfiles', @@ -115,8 +115,8 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Default profile settings - .description These apply to all profiles of a given type + .title(translate) Default profile settings + .description(translate) These apply to all profiles of a given type .list-group.mt-3.mb-3 a.list-group-item.list-group-item-action( diff --git a/tabby-settings/src/components/profilesSettingsTab.component.ts b/tabby-settings/src/components/profilesSettingsTab.component.ts index 961fd80f..f40f9168 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.ts +++ b/tabby-settings/src/components/profilesSettingsTab.component.ts @@ -3,7 +3,7 @@ import slugify from 'slugify' import deepClone from 'clone-deep' import { Component, HostBinding, Inject } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { ConfigService, HostAppService, Profile, SelectorService, ProfilesService, PromptModalComponent, PlatformService, BaseComponent, PartialProfile, ProfileProvider } from 'tabby-core' +import { ConfigService, HostAppService, Profile, SelectorService, ProfilesService, PromptModalComponent, PlatformService, BaseComponent, PartialProfile, ProfileProvider, TranslateService } from 'tabby-core' import { EditProfileModalComponent } from './editProfileModal.component' interface ProfileGroup { @@ -35,6 +35,7 @@ export class ProfilesSettingsTabComponent extends BaseComponent { private selector: SelectorService, private ngbModal: NgbModal, private platform: PlatformService, + private translate: TranslateService, ) { super() this.profileProviders.sort((a, b) => a.name.localeCompare(b.name)) @@ -58,7 +59,7 @@ export class ProfilesSettingsTabComponent extends BaseComponent { const profiles = [...this.templateProfiles, ...this.builtinProfiles, ...this.profiles] profiles.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0)) base = await this.selector.show( - 'Select a base profile to use as a template', + this.translate.instant('Select a base profile to use as a template'), profiles.map(p => ({ icon: p.icon, description: this.profilesService.getDescription(p) ?? undefined, @@ -72,14 +73,14 @@ export class ProfilesSettingsTabComponent extends BaseComponent { if (base.isTemplate) { profile.name = '' } else if (!base.isBuiltin) { - profile.name = `${base.name} copy` + profile.name = this.translate.instant('{name} copy', base) } profile.isBuiltin = false profile.isTemplate = false await this.showProfileEditModal(profile) if (!profile.name) { const cfgProxy = this.profilesService.getConfigProxyForProfile(profile) - profile.name = this.profilesService.providerForProfile(profile)?.getSuggestedName(cfgProxy) ?? `${base.name} copy` + profile.name = this.profilesService.providerForProfile(profile)?.getSuggestedName(cfgProxy) ?? this.translate.instant('{name} copy', base) } profile.id = `${profile.type}:custom:${slugify(profile.name)}:${uuidv4()}` this.config.store.profiles = [profile, ...this.config.store.profiles] @@ -122,8 +123,11 @@ export class ProfilesSettingsTabComponent extends BaseComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: `Delete "${profile.name}"?`, - buttons: ['Delete', 'Keep'], + message: this.translate.instant('Delete "{name}"?', profile), + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Keep'), + ], defaultId: 1, cancelId: 1, } @@ -156,7 +160,7 @@ export class ProfilesSettingsTabComponent extends BaseComponent { this.profileGroups.sort((a, b) => a.name?.localeCompare(b.name ?? '') ?? -1) this.profileGroups.push({ - name: 'Built-in', + name: this.translate.instant('Built-in'), profiles: this.builtinProfiles, editable: false, collapsed: false, @@ -165,7 +169,7 @@ export class ProfilesSettingsTabComponent extends BaseComponent { async editGroup (group: ProfileGroup): Promise { const modal = this.ngbModal.open(PromptModalComponent) - modal.componentInstance.prompt = 'New name' + modal.componentInstance.prompt = this.translate.instant('New name') modal.componentInstance.value = group.name const result = await modal.result if (result) { @@ -181,8 +185,11 @@ export class ProfilesSettingsTabComponent extends BaseComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: `Delete "${group.name}"?`, - buttons: ['Delete', 'Keep'], + message: this.translate.instant('Delete "{name}"?', group), + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Keep'), + ], defaultId: 1, cancelId: 1, } @@ -190,8 +197,11 @@ export class ProfilesSettingsTabComponent extends BaseComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: `Delete the group's profiles?`, - buttons: ['Move to "Ungrouped"', 'Delete'], + message: this.translate.instant(`Delete the group's profiles?`), + buttons: [ + this.translate.instant('Move to "Ungrouped"'), + this.translate.instant('Delete'), + ], defaultId: 0, cancelId: 0, } @@ -224,10 +234,10 @@ export class ProfilesSettingsTabComponent extends BaseComponent { getTypeLabel (profile: PartialProfile): string { const name = this.profilesService.providerForProfile(profile)?.name - if (name === 'Local') { + if (name === this.translate.instant('Local terminal')) { return '' } - return name ?? 'Unknown' + return name ?? this.translate.instant('Unknown') } getTypeColorClass (profile: PartialProfile): string { diff --git a/tabby-settings/src/components/releaseNotesTab.component.ts b/tabby-settings/src/components/releaseNotesTab.component.ts index 95adf489..a5b236b3 100644 --- a/tabby-settings/src/components/releaseNotesTab.component.ts +++ b/tabby-settings/src/components/releaseNotesTab.component.ts @@ -2,7 +2,7 @@ import axios from 'axios' import { marked } from 'marked' import { Component } from '@angular/core' -import { BaseTabComponent } from 'tabby-core' +import { BaseTabComponent, TranslateService } from 'tabby-core' export interface Release { name: string @@ -21,9 +21,9 @@ export class ReleaseNotesComponent extends BaseTabComponent { releases: Release[] = [] lastPage = 1 - constructor () { + constructor (translate: TranslateService) { super() - this.setTitle('Release notes') + this.setTitle(translate.instant('Release notes')) this.loadReleases(1) } diff --git a/tabby-settings/src/components/setVaultPassphraseModal.component.pug b/tabby-settings/src/components/setVaultPassphraseModal.component.pug index f2e3b2ff..bd24e68c 100644 --- a/tabby-settings/src/components/setVaultPassphraseModal.component.pug +++ b/tabby-settings/src/components/setVaultPassphraseModal.component.pug @@ -1,6 +1,6 @@ -h3.modal-header.m-0.pb-0 Set master passphrase +h3.modal-header.m-0.pb-0(translate) Set master passphrase .modal-body - .mb-2 You can change it later, but it's unrecoverable if forgotten. + .mb-2(translate) You can change it later, but it's unrecoverable if forgotten. .input-group input.form-control.form-control-lg( [type]='showPassphrase ? "text" : "password"', @@ -16,5 +16,5 @@ h3.modal-header.m-0.pb-0 Set master passphrase i.fas.fa-eye .modal-footer - button.btn.btn-primary((click)='ok()') Set passphrase - button.btn.btn-danger((click)='cancel()') Cancel + button.btn.btn-primary((click)='ok()', translate) Set passphrase + button.btn.btn-danger((click)='cancel()', translate) Cancel diff --git a/tabby-settings/src/components/settingsTab.component.pug b/tabby-settings/src/components/settingsTab.component.pug index ab7cd179..c60ab10a 100644 --- a/tabby-settings/src/components/settingsTab.component.pug +++ b/tabby-settings/src/components/settingsTab.component.pug @@ -3,7 +3,7 @@ li(ngbNavItem='application') a(ngbNavLink) i.fas.fa-fw.fa-window-maximize.mr-2 - | Application + span(translate) Application ng-template(ngbNavContent) .content-box .row @@ -23,59 +23,69 @@ i.fas.fa-sync( [class.fa-spin]='checkingForUpdate' ) - span Check for updates + span(translate) Check for updates button.btn.btn-info.mt-3.mb-2( *ngIf='updateAvailable', (click)='updater.update()', ) i.fas.fa-sync - span Update + span(translate) Update .col-12.col-md-6 .list-group.list-group-light.mb-5 button.list-group-item.list-group-item-action.link-card((click)='homeBase.reportBug()') i.fas.fa-fw.fa-bug div - div Report a problem - small.text-muted Generate a pre-filled GitHub issue + div(translate) Report a problem + small.text-muted(translate) Generate a pre-filled GitHub issue button.list-group-item.list-group-item-action.link-card((click)='homeBase.openDiscussions()') i.fas.fa-fw.fa-comments div - div Ask a question - small.text-muted On GitHub Discussions + div(translate) Ask a question + small.text-muted(translate) On GitHub Discussions button.list-group-item.list-group-item-action.link-card((click)='homeBase.openGitHub()') i.fab.fa-fw.fa-github div div GitHub - small.text-muted Source code + small.text-muted(translate) Source code button.list-group-item.list-group-item-action.link-card((click)='showReleaseNotes()') i.fas.fa-fw.fa-book div - div What's new - small.text-muted Show release notes + div(translate) What's new + small.text-muted(translate) Show release notes button.list-group-item.list-group-item-action.link-card((click)='homeBase.openTwitter()') i.fab.fa-fw.fa-twitter div - div Subscribe to updates - small.text-muted Tabby news and updates on Twitter + div(translate) Subscribe to updates + small.text-muted(translate) Tabby news and updates on Twitter - h3 Application settings + h3(translate) Application settings + .form-line + .header + .title(translate) Language + select.form-control([(ngModel)]='config.store.language', (ngModelChange)='saveConfiguration()') + option([value]='null', translate) Automatic + option( + [value]='lang.code', + *ngFor='let lang of locale.allLanguages' + ) {{lang.name|translate}} + .form-line(*ngIf='platform.isShellIntegrationSupported()') .header - .title Shell integration - .description Allows quickly opening a terminal in the selected folder + .title(translate) Shell integration + .description(translate) Allows quickly opening a terminal in the selected folder toggle([ngModel]='isShellIntegrationInstalled', (ngModelChange)='toggleShellIntegration()') .form-line(*ngIf='hostApp.platform !== Platform.Web') .header - .title Enable analytics - .description We're only tracking your Tabby and OS versions. + .title(translate) Enable analytics + .description(translate) We're only tracking your Tabby and OS versions. toggle( [(ngModel)]='config.store.enableAnalytics', (ngModelChange)='saveConfiguration(true)', @@ -83,23 +93,23 @@ .form-line(*ngIf='hostApp.platform !== Platform.Web') .header - .title Automatic Updates - .description Enable automatic installation of updates when they become available. + .title(translate) Automatic Updates + .description(translate) Enable automatic installation of updates when they become available. toggle([(ngModel)]='config.store.enableAutomaticUpdates', (ngModelChange)='saveConfiguration()') .form-line(*ngIf='hostApp.platform !== Platform.Web') .header - .title Debugging + .title(translate) Debugging button.btn.btn-secondary((click)='hostWindow.openDevTools()') i.fas.fa-bug - span Open DevTools + span(translate) Open DevTools ng-container(*ngFor='let provider of settingsProviders') li(*ngIf='provider.prioritized', [ngbNavItem]='provider.id') a(ngbNavLink) i(class='fas fa-fw mr-2 fa-{{provider.icon}}') - | {{provider.title}} + span(translate) {{provider.title}} ng-template(ngbNavContent) settings-tab-body([provider]='provider') @@ -109,24 +119,24 @@ li(*ngIf='!provider.prioritized', [ngbNavItem]='provider.id') a(ngbNavLink) i(class='fas fa-fw mr-2 fa-{{provider.icon || "puzzle-piece"}}') - | {{provider.title}} + span(translate) {{provider.title}} ng-template(ngbNavContent) settings-tab-body([provider]='provider') li(ngbNavItem='config-file') a(ngbNavLink) i.fas.fa-fw.fa-code.mr-2 - | Config file + span(translate) Config file ng-template.test(ngbNavContent) .d-flex.flex-column.w-100.h-100 .h-100.d-flex .w-100.d-flex.flex-column - h3 Config file + h3(translate) Config file textarea.form-control.h-100( [(ngModel)]='configFile' ) .w-100.d-flex.flex-column(*ngIf='showConfigDefaults') - h3 Defaults + h3(translate) Defaults textarea.form-control.h-100( [(ngModel)]='configDefaults', readonly @@ -134,20 +144,25 @@ .mt-3.d-flex button.btn.btn-primary((click)='saveConfigFile()', *ngIf='isConfigFileValid()') i.fas.fa-check.mr-2 - | Save and apply + span(translate) Save and apply button.btn.btn-primary(disabled, *ngIf='!isConfigFileValid()') i.fas.fa-exclamation-triangle.mr-2 - | Invalid syntax + span(translate) Invalid syntax button.btn.btn-secondary.ml-auto( - (click)='showConfigDefaults = !showConfigDefaults' + (click)='showConfigDefaults = !showConfigDefaults', + translate ) Show defaults button.btn.btn-secondary.ml-3( *ngIf='platform.getConfigPath()', (click)='showConfigFile()' ) i.fas.fa-external-link-square-alt.mr-2 - | Show config file + span(translate) Show config file div([ngbNavOutlet]='nav') -button.btn.btn-warning.btn-block(*ngIf='config.restartRequested', '(click)'='restartApp()') Restart the app to apply changes +button.btn.btn-warning.btn-block( + *ngIf='config.restartRequested', + (click)='restartApp()', + translate +) Restart the app to apply changes diff --git a/tabby-settings/src/components/settingsTab.component.ts b/tabby-settings/src/components/settingsTab.component.ts index 0833c98b..cc799aeb 100644 --- a/tabby-settings/src/components/settingsTab.component.ts +++ b/tabby-settings/src/components/settingsTab.component.ts @@ -12,6 +12,8 @@ import { PlatformService, HostWindowService, AppService, + LocaleService, + TranslateService, } from 'tabby-core' import { SettingsTabProvider } from '../api' @@ -43,12 +45,14 @@ export class SettingsTabComponent extends BaseTabComponent { public homeBase: HomeBaseService, public platform: PlatformService, public zone: NgZone, + public locale: LocaleService, private updater: UpdaterService, private app: AppService, @Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[], + translate: TranslateService, ) { super() - this.setTitle('Settings') + this.setTitle(translate.instant('Settings')) this.settingsProviders = config.enabledServices(this.settingsProviders) this.settingsProviders = this.settingsProviders.filter(x => !!x.getComponentType()) this.settingsProviders.sort((a, b) => a.weight - b.weight + a.title.localeCompare(b.title)) diff --git a/tabby-settings/src/components/vaultSettingsTab.component.pug b/tabby-settings/src/components/vaultSettingsTab.component.pug index f6108031..945fd1d0 100644 --- a/tabby-settings/src/components/vaultSettingsTab.component.pug +++ b/tabby-settings/src/components/vaultSettingsTab.component.pug @@ -1,27 +1,27 @@ .text-center(*ngIf='!vault.isEnabled()') i.fas.fa-key.fa-3x.m-3 - h3.m-3 Vault is not configured - .m-3 Vault is an always-encrypted container for secrets such as SSH passwords and private key passphrases. - button.btn.btn-primary.m-2((click)='enableVault()') Set master passphrase + h3.m-3(translate) Vault is not configured + .m-3(translate) Vault is an always-encrypted container for secrets such as SSH passwords and private key passphrases. + button.btn.btn-primary.m-2((click)='enableVault()', translate) Set master passphrase div(*ngIf='vault.isEnabled()') .d-flex.align-items-center.mb-3 - h3.m-0 Vault + h3.m-0(translate) Vault .d-flex.ml-auto(ngbDropdown, *ngIf='vault.isEnabled()') - button.btn.btn-secondary(ngbDropdownToggle) Options + button.btn.btn-secondary(ngbDropdownToggle, translate) Options div(ngbDropdownMenu) a(ngbDropdownItem, (click)='changePassphrase()') i.fas.fa-fw.fa-key - span Change the master passphrase + span(translate) Change the master passphrase a(ngbDropdownItem, (click)='disableVault()') i.fas.fa-fw.fa-radiation-alt - span Erase the vault + span(translate) Erase the Vault div(*ngIf='vaultContents') .text-center(*ngIf='!vaultContents.secrets.length') i.fas.fa-empty-set.fa-3x - h3.m-3 Vault is empty + h3.m-3(translate) Vault is empty .list-group .list-group-item.d-flex.align-items-center.p-1.pl-3(*ngFor='let secret of vaultContents.secrets') @@ -38,30 +38,30 @@ div(*ngIf='vault.isEnabled()') (click)='renameFile(secret)' ) i.fas.fa-fw.fa-pencil-alt - span Rename + span(translate) Rename button( ngbDropdownItem, *ngIf='secret.type === VAULT_SECRET_TYPE_FILE', (click)='replaceFileContent(secret)' ) i.fas.fa-fw.fa-file-import - span Replace + span(translate) Replace button( ngbDropdownItem, *ngIf='secret.type === VAULT_SECRET_TYPE_FILE', (click)='exportFile(secret)' ) i.fas.fa-fw.fa-file-export - span Export + span(translate) Export button(ngbDropdownItem, (click)='removeSecret(secret)') i.fas.fa-fw.fa-trash - span Delete + span(translate) Delete - h3.mt-5 Options + h3.mt-5(translate) Options .form-line .header - .title Encrypt config file - .description Puts all of Tabby's configuration into the vault + .title(translate) Encrypt config file + .description(translate) Puts all of Tabby's configuration into the vault toggle( [ngModel]='config.store.encrypted', (click)='toggleConfigEncrypted()', @@ -69,5 +69,5 @@ div(*ngIf='vault.isEnabled()') .text-center(*ngIf='!vaultContents') i.fas.fa-key.fa-3x - h3.m-3 Vault is locked - button.btn.btn-primary.m-2((click)='loadVault()') Show vault contents + h3.m-3(translate) Vault is locked + button.btn.btn-primary.m-2((click)='loadVault()', translate) Show vault contents diff --git a/tabby-settings/src/components/vaultSettingsTab.component.ts b/tabby-settings/src/components/vaultSettingsTab.component.ts index 1520c00b..5b5380bd 100644 --- a/tabby-settings/src/components/vaultSettingsTab.component.ts +++ b/tabby-settings/src/components/vaultSettingsTab.component.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Component, HostBinding } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { BaseComponent, VaultService, VaultSecret, Vault, PlatformService, ConfigService, VAULT_SECRET_TYPE_FILE, PromptModalComponent, VaultFileSecret } from 'tabby-core' +import { BaseComponent, VaultService, VaultSecret, Vault, PlatformService, ConfigService, VAULT_SECRET_TYPE_FILE, PromptModalComponent, VaultFileSecret, TranslateService } from 'tabby-core' import { SetVaultPassphraseModalComponent } from './setVaultPassphraseModal.component' @@ -21,6 +21,7 @@ export class VaultSettingsTabComponent extends BaseComponent { public config: ConfigService, private platform: PlatformService, private ngbModal: NgbModal, + private translate: TranslateService, ) { super() if (vault.isOpen()) { @@ -43,8 +44,11 @@ export class VaultSettingsTabComponent extends BaseComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: 'Delete vault contents?', - buttons: ['Delete', 'Keep'], + message: this.translate.instant('Delete vault contents?'), + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Keep'), + ], defaultId: 1, cancelId: 1, } @@ -77,16 +81,16 @@ export class VaultSettingsTabComponent extends BaseComponent { getSecretLabel (secret: VaultSecret) { if (secret.type === 'ssh:password') { - return `SSH password for ${(secret as any).key.user}@${(secret as any).key.host}:${(secret as any).key.port}` + return this.translate.instant('SSH password for {user}@{host}:{port}', (secret as any).key) } if (secret.type === 'ssh:key-passphrase') { - return `Passphrase for a private key with hash ${(secret as any).key.hash.substring(0, 8)}...` + return this.translate.instant('Passphrase for a private key with hash {hash}...', { hash: (secret as any).key.hash.substring(0, 8) }) } if (secret.type === VAULT_SECRET_TYPE_FILE) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - return `File: ${(secret as VaultFileSecret).key.description}` + return this.translate.instant('File: {description}', (secret as VaultFileSecret).key) } - return `Unknown secret of type ${secret.type} for ${JSON.stringify(secret.key)}` + return this.translate.instant('Unknown secret of type {type} for {key}', { type: secret.type, key: JSON.stringify(secret.key) }) } removeSecret (secret: VaultSecret) { @@ -111,7 +115,7 @@ export class VaultSettingsTabComponent extends BaseComponent { async renameFile (secret: VaultFileSecret) { const modal = this.ngbModal.open(PromptModalComponent) - modal.componentInstance.prompt = 'New name' + modal.componentInstance.prompt = this.translate.instant('New name') modal.componentInstance.value = secret.key.description const description = (await modal.result)?.value diff --git a/tabby-settings/src/components/windowSettingsTab.component.pug b/tabby-settings/src/components/windowSettingsTab.component.pug index a4c1ae94..f7ccc1ab 100644 --- a/tabby-settings/src/components/windowSettingsTab.component.pug +++ b/tabby-settings/src/components/windowSettingsTab.component.pug @@ -1,8 +1,8 @@ -h3.mb-3 Window +h3.mb-3(translate) Window .form-line .header - .title Theme + .title(translate) Theme select.form-control( [(ngModel)]='config.store.appearance.theme', (ngModelChange)='saveConfiguration()', @@ -12,8 +12,8 @@ h3.mb-3 Window .form-line(*ngIf='hostApp.platform === Platform.Web') .header - .title Ask before closing the browser tab - .description Prevents accidental closing + .title(translate) Ask before closing the browser tab + .description(translate) Prevents accidental closing toggle( [(ngModel)]='config.store.web.preventAccidentalTabClosure', (ngModelChange)='saveConfiguration()', @@ -22,9 +22,9 @@ h3.mb-3 Window .form-line(*ngIf='platform.supportsWindowControls') .header - .title(*ngIf='hostApp.platform !== Platform.macOS') Acrylic background - .title(*ngIf='hostApp.platform === Platform.macOS') Vibrancy - .description Gives the window a blurred transparent background + .title(*ngIf='hostApp.platform !== Platform.macOS', translate) Acrylic background + .title(*ngIf='hostApp.platform === Platform.macOS', translate) Vibrancy + .description(translate) Gives the window a blurred transparent background toggle( [(ngModel)]='config.store.appearance.vibrancy', @@ -33,7 +33,7 @@ h3.mb-3 Window .form-line(*ngIf='config.store.appearance.vibrancy && isFluentVibrancySupported') .header - .title Background type + .title(translate) Background type .btn-group( [(ngModel)]='config.store.appearance.vibrancyType', (ngModelChange)='saveConfiguration()', @@ -45,18 +45,18 @@ h3.mb-3 Window ngbButton, [value]='"blur"' ) - | Blur + span(translate) Blur label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"fluent"' ) - | Fluent + span Fluent .form-line(*ngIf='platform.supportsWindowControls') .header - .title Opacity + .title(translate) Opacity input( type='range', [(ngModel)]='config.store.appearance.opacity', @@ -68,8 +68,8 @@ h3.mb-3 Window .form-line(*ngIf='platform.supportsWindowControls') .header - .title Window frame - .description Whether a custom window or an OS native window should be used + .title(translate) Window frame + .description(translate) Whether a custom window or an OS native window should be used .btn-group( [(ngModel)]='config.store.appearance.frame', @@ -82,28 +82,28 @@ h3.mb-3 Window ngbButton, [value]='"native"' ) - | Native + span(translate) Native label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"thin"' ) - | Thin + span(translate) Thin label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"full"' ) - | Full + span(translate) Full -h3.mt-4 Docking +h3.mt-4(translate) Docking .form-line(*ngIf='docking') .header - .title Dock the terminal - .description Snaps the window to a side of the screen + .title(translate) Dock the terminal + .description(translate) Snaps the window to a side of the screen .btn-group( [(ngModel)]='config.store.appearance.dock', @@ -116,40 +116,40 @@ h3.mt-4 Docking ngbButton, [value]='"off"' ) - | Off + span(translate) Off label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"top"' ) - | Top + span(translate) Top label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"left"' ) - | Left + span(translate) Left label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"right"' ) - | Right + span(translate) Right label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"bottom"' ) - | Bottom + span(translate) Bottom .ml-5.form-line(*ngIf='docking && config.store.appearance.dock != "off"') .header - .title Display on - .description Snaps the window to a side of the screen + .title(translate) Display on + .description(translate) Snaps the window to a side of the screen div( [(ngModel)]='config.store.appearance.dockScreen', @@ -162,7 +162,7 @@ h3.mt-4 Docking ngbButton, value='current' ) - | Current + span(translate) Current label.btn.btn-secondary(*ngFor='let screen of screens', ngbButtonLabel) input( type='radio', @@ -173,8 +173,8 @@ h3.mt-4 Docking .ml-5.form-line(*ngIf='docking && config.store.appearance.dock != "off"') .header - .title Dock always on top - .description Keep docked terminal always on top + .title(translate) Dock always on top + .description(translate) Keep docked terminal always on top toggle( [(ngModel)]='config.store.appearance.dockAlwaysOnTop', (ngModelChange)='saveConfiguration(); docking.dock()', @@ -182,7 +182,7 @@ h3.mt-4 Docking .ml-5.form-line(*ngIf='docking && config.store.appearance.dock != "off"') .header - .title Docked terminal size + .title(translate) Docked terminal size input( type='range', [(ngModel)]='config.store.appearance.dockFill', @@ -194,7 +194,7 @@ h3.mt-4 Docking .ml-5.form-line(*ngIf='docking && config.store.appearance.dock != "off"') .header - .title Docked terminal space + .title(translate) Docked terminal space input( type='range', [(ngModel)]='config.store.appearance.dockSpace', @@ -206,18 +206,18 @@ h3.mt-4 Docking .ml-5.form-line(*ngIf='docking && config.store.appearance.dock != "off"') .header - .title Hide dock on blur - .description Hides the docked terminal when you click away. + .title(translate) Hide dock on blur + .description(translate) Hides the docked terminal when you click away. toggle( [(ngModel)]='config.store.appearance.dockHideOnBlur', (ngModelChange)='saveConfiguration(); ', ) -h3.mt-4 Tabs +h3.mt-4(translate) Tabs .form-line .header - .title Tabs location + .title(translate) Tabs location .btn-group( [(ngModel)]='config.store.appearance.tabsLocation', (ngModelChange)='saveConfiguration()', @@ -229,32 +229,32 @@ h3.mt-4 Tabs ngbButton, [value]='"top"' ) - | Top + span(translate) Top label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"bottom"' ) - | Bottom + span(translate) Bottom label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"left"' ) - | Left + span(translate) Left label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"right"' ) - | Right + span(translate) Right .form-line .header - .title Tabs width + .title(translate) Tabs width .btn-group( [(ngModel)]='config.store.appearance.flexTabs', (ngModelChange)='saveConfiguration()', @@ -266,18 +266,18 @@ h3.mt-4 Tabs ngbButton, [value]='true' ) - | Dynamic + span(translate) Dynamic label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='false' ) - | Fixed + span(translate) Fixed .form-line .header - .title Hide tab index + .title(translate) Hide tab index toggle( [(ngModel)]='config.store.terminal.hideTabIndex', @@ -286,7 +286,7 @@ h3.mt-4 Tabs .form-line .header - .title Hide tab close button + .title(translate) Hide tab close button toggle( [(ngModel)]='config.store.terminal.hideCloseButton', @@ -297,8 +297,8 @@ h3.mt-4 Hacks .form-line .header - .title Disable GPU acceleration - .description Tick this if you're experiencing aliasing, ghosting or other visual issues + .title(translate) Disable GPU acceleration + .description(translate) Tick this if you're experiencing aliasing, ghosting or other visual issues toggle( [(ngModel)]='config.store.hacks.disableGPU', diff --git a/tabby-settings/src/hotkeys.ts b/tabby-settings/src/hotkeys.ts index 71837897..8e8c6080 100644 --- a/tabby-settings/src/hotkeys.ts +++ b/tabby-settings/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,10 +7,12 @@ export class SettingsHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'settings', - name: 'Open Settings', + name: this.translate.instant('Open Settings'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-settings/src/settings.ts b/tabby-settings/src/settings.ts index b10a4253..f96e4d2a 100644 --- a/tabby-settings/src/settings.ts +++ b/tabby-settings/src/settings.ts @@ -5,13 +5,16 @@ import { WindowSettingsTabComponent } from './components/windowSettingsTab.compo import { VaultSettingsTabComponent } from './components/vaultSettingsTab.component' import { ConfigSyncSettingsTabComponent } from './components/configSyncSettingsTab.component' import { ProfilesSettingsTabComponent } from './components/profilesSettingsTab.component' +import { TranslateService } from 'tabby-core' /** @hidden */ @Injectable() export class HotkeySettingsTabProvider extends SettingsTabProvider { id = 'hotkeys' icon = 'keyboard' - title = 'Hotkeys' + title = this.translate.instant('Hotkeys') + + constructor (private translate: TranslateService) { super() } getComponentType (): any { return HotkeySettingsTabComponent @@ -24,7 +27,9 @@ export class HotkeySettingsTabProvider extends SettingsTabProvider { export class WindowSettingsTabProvider extends SettingsTabProvider { id = 'window' icon = 'window-maximize' - title = 'Window' + title = this.translate.instant('Window') + + constructor (private translate: TranslateService) { super() } getComponentType (): any { return WindowSettingsTabComponent @@ -50,9 +55,11 @@ export class VaultSettingsTabProvider extends SettingsTabProvider { export class ProfilesSettingsTabProvider extends SettingsTabProvider { id = 'profiles' icon = 'window-restore' - title = 'Profiles & connections' + title = this.translate.instant('Profiles & connections') prioritized = true + constructor (private translate: TranslateService) { super() } + getComponentType (): any { return ProfilesSettingsTabComponent } @@ -63,7 +70,9 @@ export class ProfilesSettingsTabProvider extends SettingsTabProvider { export class ConfigSyncSettingsTabProvider extends SettingsTabProvider { id = 'config-sync' icon = 'cloud' - title = 'Config sync' + title = this.translate.instant('Config sync') + + constructor (private translate: TranslateService) { super() } getComponentType (): any { return ConfigSyncSettingsTabComponent diff --git a/tabby-ssh/src/components/keyboardInteractiveAuthPanel.component.pug b/tabby-ssh/src/components/keyboardInteractiveAuthPanel.component.pug index 793c3c62..4de32bc7 100644 --- a/tabby-ssh/src/components/keyboardInteractiveAuthPanel.component.pug +++ b/tabby-ssh/src/components/keyboardInteractiveAuthPanel.component.pug @@ -1,5 +1,5 @@ .d-flex - strong Keyboard-interactive auth + strong(translate) Keyboard-interactive auth .ml-2 {{prompt.name}} .prompt-text {{prompt.prompts[step].prompt}} diff --git a/tabby-ssh/src/components/sftpDeleteModal.component.pug b/tabby-ssh/src/components/sftpDeleteModal.component.pug index 0c9913e4..ce392c5b 100644 --- a/tabby-ssh/src/components/sftpDeleteModal.component.pug +++ b/tabby-ssh/src/components/sftpDeleteModal.component.pug @@ -1,6 +1,6 @@ .modal-body - label Deleting + label(translate) Deleting .no-wrap {{progressMessage}} .modal-footer - button.btn.btn-danger((click)='cancel()') Cancel + button.btn.btn-danger((click)='cancel()', translate) Cancel diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 54df59f9..7007b5f5 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -8,21 +8,21 @@ button.btn.btn-link.btn-sm.d-flex((click)='upload()') i.fas.fa-upload.mr-1 - div Upload + div(translate) Upload button.btn.btn-link.btn-close((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')} .body(dropZone, (transfer)='uploadOne($event)') - div(*ngIf='!sftp') Connecting + div(*ngIf='!sftp', translate) Connecting div(*ngIf='sftp') - div(*ngIf='fileList === null') Loading + div(*ngIf='fileList === null', translate) Loading .list-group.list-group-light(*ngIf='fileList !== null') .list-group-item.list-group-item-action.d-flex.align-items-center( *ngIf='path !== "/"', (click)='goUp()' ) i.fas.fa-fw.fa-level-up-alt - div Go up + div(translate) Go up .list-group-item.list-group-item-action.d-flex.align-items-center( *ngFor='let item of fileList', (contextmenu)='showContextMenu(item, $event)', diff --git a/tabby-ssh/src/components/sshPortForwardingConfig.component.pug b/tabby-ssh/src/components/sshPortForwardingConfig.component.pug index 9174700a..2feff743 100644 --- a/tabby-ssh/src/components/sshPortForwardingConfig.component.pug +++ b/tabby-ssh/src/components/sshPortForwardingConfig.component.pug @@ -2,13 +2,13 @@ .list-group-item.d-flex.align-items-center(*ngFor='let fw of model') div .ms-2.d-flex.align-items-center - strong(*ngIf='fw.type === PortForwardType.Local') Local - strong(*ngIf='fw.type === PortForwardType.Remote') Remote - strong(*ngIf='fw.type === PortForwardType.Dynamic') Dynamic + strong(*ngIf='fw.type === PortForwardType.Local', translate) Local + strong(*ngIf='fw.type === PortForwardType.Remote', translate) Remote + strong(*ngIf='fw.type === PortForwardType.Dynamic', translate) Dynamic .ml-3 {{fw.host}}:{{fw.port}} .ml-2 → .ml-2(*ngIf='fw.type !== PortForwardType.Dynamic') {{fw.targetAddress}}:{{fw.targetPort}} - .ml-2(*ngIf='fw.type === PortForwardType.Dynamic') SOCKS proxy + .ml-2(*ngIf='fw.type === PortForwardType.Dynamic', translate) SOCKS proxy div {{fw.description}} button.btn.btn-link.hover-reveal.ml-auto((click)='remove(fw)') i.fas.fa-trash-alt @@ -22,7 +22,7 @@ h5 Add a port forward input.form-control(type='number', [(ngModel)]='newForward.port') .input-group-append .input-group-text → - .input-group-append.input-group-text(style='flex: 3 1 0') SOCKS proxy + .input-group-append.input-group-text(style='flex: 3 1 0', translate) SOCKS proxy .input-group.mb-2(*ngIf='newForward.type !== PortForwardType.Dynamic') input.form-control(type='text', [(ngModel)]='newForward.host') @@ -50,22 +50,22 @@ h5 Add a port forward ngbButton, [value]='PortForwardType.Local' ) - | Local + span(translate) Local label.btn.btn-secondary.m-0(ngbButtonLabel) input( type='radio', ngbButton, [value]='PortForwardType.Remote' ) - | Remote + span(translate) Remote label.btn.btn-secondary.m-0(ngbButtonLabel) input( type='radio', ngbButton, [value]='PortForwardType.Dynamic' ) - | Dynamic + span(translate) Dynamic button.btn.btn-primary((click)='addForward()') i.fas.fa-check.mr-2 - span Forward port + span(translate) Forward port diff --git a/tabby-ssh/src/components/sshPortForwardingModal.component.pug b/tabby-ssh/src/components/sshPortForwardingModal.component.pug index e4a3f2fb..e3fe24e1 100644 --- a/tabby-ssh/src/components/sshPortForwardingModal.component.pug +++ b/tabby-ssh/src/components/sshPortForwardingModal.component.pug @@ -1,5 +1,5 @@ .modal-header(*ngIf='session.forwardedPorts.length') - h5.m-0 Forwarded ports + h5.m-0(translate) Forwarded ports .modal-body.pt-0 ssh-port-forwarding-config( diff --git a/tabby-ssh/src/components/sshProfileSettings.component.pug b/tabby-ssh/src/components/sshProfileSettings.component.pug index 099fb06d..a3ccd2a4 100644 --- a/tabby-ssh/src/components/sshProfileSettings.component.pug +++ b/tabby-ssh/src/components/sshProfileSettings.component.pug @@ -1,50 +1,51 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) General + a(ngbNavLink, translate) General ng-template(ngbNavContent) .d-flex.w-100.mt-3 .form-group.mr-2( ngbDropdown ) - label Connection + label(translate) Connection button.btn.btn-secondary.d-block(ngbDropdownToggle) {{getConnectionDropdownTitle()}} div(ngbDropdownMenu) button.dropdown-item( (click)='connectionMode = "direct"', + translate ) Direct button.dropdown-item( *ngIf='hostApp.platform !== Platform.Web', (click)='connectionMode = "proxyCommand"', ) div Proxy command - .text-muted Command's stdin/stdout is used instead of a network connection + .text-muted(translate) Command's stdin/stdout is used instead of a network connection button.dropdown-item( (click)='connectionMode = "jumpHost"', ) - div Jump host - .text-muted Connect to a different host first and use it as a proxy + div(translate) Jump host + .text-muted(translate) Connect to a different host first and use it as a proxy button.dropdown-item( (click)='connectionMode = "socksProxy"', ) - div SOCKS proxy - .text-muted Connect through a proxy server + div(translate) SOCKS proxy + .text-muted(translate) Connect through a proxy server .form-group.w-100(*ngIf='connectionMode === "proxyCommand"') - label Proxy command + label(translate) Proxy command input.form-control( type='text', [(ngModel)]='profile.options.proxyCommand', ) .form-group.w-100.mr-2(*ngIf='connectionMode !== "proxyCommand"') - label Host + label(translate) Host input.form-control( type='text', [(ngModel)]='profile.options.host', ) .form-group(*ngIf='connectionMode !== "proxyCommand"') - label Port + label(translate) Port input.form-control( type='number', placeholder='22', @@ -52,22 +53,22 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) .form-group(*ngIf='connectionMode === "jumpHost"') - label Jump host + label(translate) Jump host select.form-control([(ngModel)]='profile.options.jumpHost') - option([ngValue]='null') Select + option([ngValue]='null', translate) Select option([ngValue]='x.id', *ngFor='let x of jumpHosts') {{x.name}} .d-flex.w-100(*ngIf='connectionMode === "socksProxy"') .form-group.w-100.mr-2 - label SOCKS proxy host + label(translate) SOCKS proxy host input.form-control( type='text', [(ngModel)]='profile.options.socksProxyHost', ) .form-group - label SOCKS proxy port + label(translate) SOCKS proxy port input.form-control( type='number', placeholder='5000', @@ -75,7 +76,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) .form-group - label Username + label(translate) Username input.form-control( type='text', placeholder='Ask every time', @@ -83,7 +84,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) .form-group - label Authentication method + label(translate) Authentication method .btn-group.mt-1.w-100( [(ngModel)]='profile.options.auth', @@ -92,38 +93,38 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') label.btn.btn-secondary(ngbButtonLabel) input(type='radio', ngbButton, [value]='null') i.far.fa-lightbulb - .m-0 Auto + .m-0(translate) Auto label.btn.btn-secondary(ngbButtonLabel) input(type='radio', ngbButton, [value]='"password"') i.fas.fa-font - .m-0 Password + .m-0(translate) Password label.btn.btn-secondary(ngbButtonLabel) input(type='radio', ngbButton, [value]='"publicKey"') i.fas.fa-key - .m-0 Key + .m-0(translate) Key label.btn.btn-secondary(ngbButtonLabel, ng:if='hostApp.platform !== Platform.Web') input(type='radio', ngbButton, [value]='"agent"') i.fas.fa-user-secret - .m-0 Agent + .m-0(translate) Agent label.btn.btn-secondary(ngbButtonLabel) input(type='radio', ngbButton, [value]='"keyboardInteractive"') i.far.fa-keyboard - .m-0 Interactive + .m-0(translate) Interactive .form-line(*ngIf='profile.options.user && (!profile.options.auth || profile.options.auth === "password")') .header - .title Password - .description(*ngIf='!hasSavedPassword') Save a password in the keychain - .description(*ngIf='hasSavedPassword') There is a saved password for this connection + .title(translate) Password + .description(*ngIf='!hasSavedPassword', translate) Save a password in the keychain + .description(*ngIf='hasSavedPassword', translate) There is a saved password for this connection button.btn.btn-success.ml-4(*ngIf='!hasSavedPassword', (click)='setPassword()') i.fas.fa-key - span Set password + span(translate) Set password button.btn.btn-danger.ml-4(*ngIf='hasSavedPassword', (click)='clearSavedPassword()') i.fas.fa-trash-alt - span Forget + span(translate) Forget .form-group(*ngIf='!profile.options.auth || profile.options.auth === "publicKey"') - label Private keys + label(translate) Private keys .list-group.mb-2 .list-group-item.d-flex.align-items-center.p-1.pl-3(*ngFor='let path of profile.options.privateKeys') i.fas.fa-key @@ -132,10 +133,10 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') i.fas.fa-trash button.btn.btn-secondary((click)='addPrivateKey()') i.fas.fa-folder-open - span Add a private key + span(translate) Add a private key li(ngbNavItem) - a(ngbNavLink) Ports + a(ngbNavLink, translate) Ports ng-template(ngbNavContent) ssh-port-forwarding-config( [model]='profile.options.forwardedPorts', @@ -144,33 +145,33 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) li(ngbNavItem) - a(ngbNavLink) Advanced + a(ngbNavLink, translate) Advanced ng-template(ngbNavContent) .form-line(ng:if='hostApp.platform !== Platform.Web') .header - .title X11 forwarding + .title(translate) X11 forwarding toggle([(ngModel)]='profile.options.x11') .form-line(ng:if='hostApp.platform !== Platform.Web') .header - .title Agent forwarding + .title(translate) Agent forwarding toggle([(ngModel)]='profile.options.agentForward') .form-line .header - .title Skip MoTD/banner + .title(translate) Skip MoTD/banner .description Will prevent the SSH greeting from showing up toggle([(ngModel)]='profile.options.skipBanner') .form-line .header - .title Reuse session for multiple tabs + .title(translate) Reuse session for multiple tabs .description Multiplex multiple shells through the same connection toggle([(ngModel)]='profile.options.reuseSession') .form-line .header - .title Keep Alive Interval (Milliseconds) + .title(translate) Keep Alive Interval (Milliseconds) input.form-control( type='number', placeholder='0', @@ -179,7 +180,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Max Keep Alive Count + .title(translate) Max Keep Alive Count input.form-control( type='number', placeholder='3', @@ -188,7 +189,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line .header - .title Ready Timeout (Milliseconds) + .title(translate) Ready Timeout (Milliseconds) input.form-control( type='number', placeholder='20000', @@ -196,18 +197,18 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ) li(ngbNavItem) - a(ngbNavLink) Ciphers + a(ngbNavLink, translate) Ciphers ng-template(ngbNavContent) .form-line.align-items-start .header - .title Ciphers + .title(translate) Ciphers .w-75 div(*ngFor='let alg of supportedAlgorithms.cipher') checkbox([text]='alg', [(ngModel)]='algorithms.cipher[alg]') .form-line.align-items-start .header - .title Key exchange + .title(translate) Key exchange .w-75 div(*ngFor='let alg of supportedAlgorithms.kex') checkbox([text]='alg', [(ngModel)]='algorithms.kex[alg]') @@ -221,13 +222,13 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') .form-line.align-items-start .header - .title Host key + .title(translate) Host key .w-75 div(*ngFor='let alg of supportedAlgorithms.serverHostKey') checkbox([text]='alg', [(ngModel)]='algorithms.serverHostKey[alg]') li(ngbNavItem) - a(ngbNavLink) Login scripts + a(ngbNavLink, translate) Login scripts ng-template(ngbNavContent) login-scripts-settings([options]='profile.options', #loginScriptsSettings) diff --git a/tabby-ssh/src/components/sshSettingsTab.component.pug b/tabby-ssh/src/components/sshSettingsTab.component.pug index 2f49e9ea..dd261773 100644 --- a/tabby-ssh/src/components/sshSettingsTab.component.pug +++ b/tabby-ssh/src/components/sshSettingsTab.component.pug @@ -2,7 +2,7 @@ h3 SSH .form-line .header - .title Warn when closing active connections + .title(translate) Warn when closing active connections toggle( [(ngModel)]='config.store.ssh.warnOnClose', (ngModelChange)='config.save()', @@ -10,8 +10,8 @@ h3 SSH .form-line(*ngIf='hostApp.platform === Platform.Windows') .header - .title WinSCP path - .description When WinSCP is detected, you can launch an SCP session from the context menu. + .title(translate) WinSCP path + .description(translate) When WinSCP is detected, you can launch an SCP session from the context menu. input.form-control( type='text', placeholder='Auto-detect', @@ -21,20 +21,20 @@ h3 SSH .form-line(*ngIf='hostApp.platform === Platform.Windows') .header - .title Agent type - .description Forces a specific SSH agent connection type. + .title(translate) Agent type + .description(translate) Forces a specific SSH agent connection type. select.form-control( [(ngModel)]='config.store.ssh.agentType', (ngModelChange)='config.save()', ) - option(value='auto') Automatic + option(value='auto', translate) Automatic option(value='pageant') Pageant - option(value='pipe') Named pipe + option(value='pipe', translate) Named pipe .form-line(*ngIf='config.store.ssh.agentType === "pipe"') .header - .title Agent pipe path - .description Sets the SSH agent's named pipe path. + .title(translate) Agent pipe path + .description(translate) Sets the SSH agent's named pipe path. input.form-control( type='text', placeholder='Default: \\\\.\\pipe\\openssh-ssh-agent', @@ -44,8 +44,8 @@ h3 SSH .form-line .header - .title Override X11 display - .description Path or address of the local X11 socket + .title(translate) Override X11 display + .description(translate) Path or address of the local X11 socket input.form-control( type='text', [placeholder]='defaultX11Display', @@ -53,4 +53,4 @@ h3 SSH (ngModelChange)='config.save()' ) -.alert.alert-info SSH connection management is now done through the #[strong Profiles & connections] tab +.alert.alert-info(translate) SSH connection management is now done through the #[strong Profiles & connections] tab diff --git a/tabby-ssh/src/components/sshTab.component.pug b/tabby-ssh/src/components/sshTab.component.pug index 136211fc..d30eeb96 100644 --- a/tabby-ssh/src/components/sshTab.component.pug +++ b/tabby-ssh/src/components/sshTab.component.pug @@ -17,24 +17,24 @@ .bg-dark(ngbDropdownMenu) a.d-flex.align-items-center(ngbDropdownItem, (click)='platform.openExternal("https://tabby.sh/go/cwd-detection")') .mr-auto - strong Working directory detection - div Learn how to allow Tabby to detect remote shell's working directory. + strong(translate) Working directory detection + div(translate) Learn how to allow Tabby to detect remote shell's working directory. i.fas.fa-arrow-right.ml-4 button.btn.btn-sm.btn-link.mr-2((click)='reconnect()') i.fas.fa-redo - span Reconnect + span(translate) Reconnect button.btn.btn-sm.btn-link.mr-2((click)='openSFTP()', *ngIf='session && session.open') i.far.fa-folder-open - span SFTP + span(translate) SFTP button.btn.btn-sm.btn-link( *ngIf='session && session.open && hostApp.platform !== Platform.Web', (click)='showPortForwarding()' ) i.fas.fa-plug - span Ports + span(translate) Ports sftp-panel.bg-dark( diff --git a/tabby-ssh/src/components/sshTab.component.ts b/tabby-ssh/src/components/sshTab.component.ts index 822c2f35..33f3c86c 100644 --- a/tabby-ssh/src/components/sshTab.component.ts +++ b/tabby-ssh/src/components/sshTab.component.ts @@ -2,7 +2,7 @@ import colors from 'ansi-colors' import { Component, Injector, HostListener } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { first } from 'rxjs' -import { Platform, ProfilesService, RecoveryToken } from 'tabby-core' +import { Platform, ProfilesService, RecoveryToken, TranslateService } from 'tabby-core' import { BaseTerminalTabComponent } from 'tabby-terminal' import { SSHService } from '../services/ssh.service' import { KeyboardInteractivePrompt, SSHSession } from '../session/ssh' @@ -36,6 +36,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent { private ngbModal: NgbModal, private profilesService: ProfilesService, private sshMultiplexer: SSHMultiplexerService, + private translate: TranslateService, ) { super(injector) this.sessionChanged$.subscribe(() => { @@ -140,7 +141,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent { if (!session.open) { this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` Connecting to ${session.profile.options.host}\r\n`) - this.startSpinner('Connecting') + this.startSpinner(this.translate.instant('Connecting')) try { await session.start() @@ -172,7 +173,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent { this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` ${this.sshSession?.profile.options.host}: session closed\r\n`) if (!this.reconnectOffered) { this.reconnectOffered = true - this.write('Press any key to reconnect\r\n') + this.write(this.translate.instant('Press any key to reconnect') + '\r\n') this.input$.pipe(first()).subscribe(() => { if (!this.session?.open && this.reconnectOffered) { this.reconnect() @@ -239,8 +240,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent { return (await this.platform.showMessageBox( { type: 'warning', - message: `Disconnect from ${this.profile?.options.host}?`, - buttons: ['Disconnect', 'Do not close'], + message: this.translate.instant('Disconnect from {host}?', this.profile?.options), + buttons: [ + this.translate.instant('Disconnect'), + this.translate.instant('Do not close'), + ], defaultId: 0, cancelId: 1, } diff --git a/tabby-ssh/src/hotkeys.ts b/tabby-ssh/src/hotkeys.ts index 658d06c3..50175468 100644 --- a/tabby-ssh/src/hotkeys.ts +++ b/tabby-ssh/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,14 +7,16 @@ export class SSHHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'restart-ssh-session', - name: 'Restart current SSH session', + name: this.translate.instant('Restart current SSH session'), }, { id: 'launch-winscp', - name: 'Launch WinSCP for current SSH session', + name: this.translate.instant('Launch WinSCP for current SSH session'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-ssh/src/profiles.ts b/tabby-ssh/src/profiles.ts index a727b5eb..4fb2fd4d 100644 --- a/tabby-ssh/src/profiles.ts +++ b/tabby-ssh/src/profiles.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { ProfileProvider, NewTabParameters, PartialProfile } from 'tabby-core' +import { ProfileProvider, NewTabParameters, PartialProfile, TranslateService } from 'tabby-core' import * as ALGORITHMS from 'ssh2/lib/protocol/constants' import { SSHProfileSettingsComponent } from './components/sshProfileSettings.component' import { SSHTabComponent } from './components/sshTab.component' @@ -45,7 +45,8 @@ export class SSHProfilesService extends ProfileProvider { } constructor ( - private passwordStorage: PasswordStorageService + private passwordStorage: PasswordStorageService, + private translate: TranslateService, ) { super() for (const k of Object.values(SSHAlgorithmType)) { @@ -71,7 +72,7 @@ export class SSHProfilesService extends ProfileProvider { { id: `ssh:template`, type: 'ssh', - name: 'SSH connection', + name: this.translate.instant('SSH connection'), icon: 'fas fa-desktop', options: { host: '', diff --git a/tabby-ssh/src/session/ssh.ts b/tabby-ssh/src/session/ssh.ts index 7ae50807..acdb8304 100644 --- a/tabby-ssh/src/session/ssh.ts +++ b/tabby-ssh/src/session/ssh.ts @@ -7,7 +7,7 @@ import colors from 'ansi-colors' import stripAnsi from 'strip-ansi' import { Injector, NgZone } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { ConfigService, FileProvidersService, HostAppService, NotificationsService, Platform, PlatformService, wrapPromise, PromptModalComponent, LogService, Logger } from 'tabby-core' +import { ConfigService, FileProvidersService, HostAppService, NotificationsService, Platform, PlatformService, wrapPromise, PromptModalComponent, LogService, Logger, TranslateService } from 'tabby-core' import { Socket } from 'net' import { Client, ClientChannel, SFTPWrapper } from 'ssh2' import { Subject, Observable } from 'rxjs' @@ -85,6 +85,7 @@ export class SSHSession { constructor ( private injector: Injector, + private translate: TranslateService, public profile: SSHProfile, ) { this.logger = injector.get(LogService).create(`ssh-${profile.options.host}-${profile.options.port}`) @@ -398,7 +399,7 @@ export class SSHSession { } if (method.type === 'password') { if (this.profile.options.password) { - this.emitServiceMessage('Using preset password') + this.emitServiceMessage(this.translate.instant('Using preset password')) return { type: 'password', username: this.authUsername, @@ -409,7 +410,7 @@ export class SSHSession { if (!this.keychainPasswordUsed && this.profile.options.user) { const password = await this.passwordStorage.loadPassword(this.profile) if (password) { - this.emitServiceMessage('Trying saved password') + this.emitServiceMessage(this.translate.instant('Trying saved password')) this.keychainPasswordUsed = true return { type: 'password', @@ -591,14 +592,10 @@ export class SSHSession { modal.componentInstance.password = true modal.componentInstance.showRememberCheckbox = true - try { - const result = await modal.result - passphrase = result?.value - if (passphrase && result.remember) { - this.passwordStorage.savePrivateKeyPassword(keyHash, passphrase) - } - } catch { - throw e + const result = await modal.result + passphrase = result?.value + if (passphrase && result.remember) { + this.passwordStorage.savePrivateKeyPassword(keyHash, passphrase) } } else { this.notifications.error('Could not read the private key', e.toString()) diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index 726a4498..b1e0cff9 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { MenuItemOptions, PlatformService } from 'tabby-core' +import { MenuItemOptions, PlatformService, TranslateService } from 'tabby-core' import { SFTPSession, SFTPFile } from './session/sftp' import { SFTPContextMenuItemProvider } from './api' import { SFTPDeleteModalComponent } from './components/sftpDeleteModal.component' @@ -15,6 +15,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { constructor ( private platform: PlatformService, private ngbModal: NgbModal, + private translate: TranslateService, ) { super() } @@ -25,16 +26,19 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { click: async () => { if ((await this.platform.showMessageBox({ type: 'warning', - message: `Delete ${item.fullPath}?`, + message: this.translate.instant('Delete {fullPath}?', item), defaultId: 0, cancelId: 1, - buttons: ['Delete', 'Cancel'], + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Cancel'), + ], })).response === 0) { await this.deleteItem(item, panel.sftp) panel.navigate(panel.path) } }, - label: 'Delete', + label: this.translate.instant('Delete'), }, ] } diff --git a/tabby-ssh/src/tabContextMenu.ts b/tabby-ssh/src/tabContextMenu.ts index bf96a32c..28ab74be 100644 --- a/tabby-ssh/src/tabContextMenu.ts +++ b/tabby-ssh/src/tabContextMenu.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, MenuItemOptions } from 'tabby-core' +import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, MenuItemOptions, TranslateService } from 'tabby-core' import { SSHTabComponent } from './components/sshTab.component' import { SSHService } from './services/ssh.service' @@ -12,6 +12,7 @@ export class SFTPContextMenu extends TabContextMenuItemProvider { constructor ( private hostApp: HostAppService, private ssh: SSHService, + private translate: TranslateService, ) { super() } @@ -21,14 +22,14 @@ export class SFTPContextMenu extends TabContextMenuItemProvider { return [] } const items = [{ - label: 'Open SFTP panel', + label: this.translate.instant('Open SFTP panel'), click: () => { tab.openSFTP() }, }] if (this.hostApp.platform === Platform.Windows && this.ssh.getWinSCPPath()) { items.push({ - label: 'Launch WinSCP', + label: this.translate.instant('Launch WinSCP'), click: (): void => { this.ssh.launchWinSCP(tab.sshSession!) }, diff --git a/tabby-telnet/src/components/telnetProfileSettings.component.pug b/tabby-telnet/src/components/telnetProfileSettings.component.pug index 35cc448d..bbea7deb 100644 --- a/tabby-telnet/src/components/telnetProfileSettings.component.pug +++ b/tabby-telnet/src/components/telnetProfileSettings.component.pug @@ -1,16 +1,16 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') li(ngbNavItem) - a(ngbNavLink) General + a(ngbNavLink, translate) General ng-template(ngbNavContent) .form-group - label Host + label(translate) Host input.form-control( type='text', [(ngModel)]='profile.options.host', ) .form-group - label Port + label(translate) Port input.form-control( type='number', placeholder='22', @@ -20,7 +20,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') stream-processing-settings([options]='profile.options') li(ngbNavItem) - a(ngbNavLink) Login scripts + a(ngbNavLink, translate) Login scripts ng-template(ngbNavContent) login-scripts-settings([options]='profile.options') diff --git a/tabby-telnet/src/components/telnetTab.component.pug b/tabby-telnet/src/components/telnetTab.component.pug index a3e8dd16..521cbd0e 100644 --- a/tabby-telnet/src/components/telnetTab.component.pug +++ b/tabby-telnet/src/components/telnetTab.component.pug @@ -8,4 +8,4 @@ button.btn.btn-sm.btn-link.mr-2((click)='reconnect()') i.fas.fa-redo - span Reconnect + span(translate) Reconnect diff --git a/tabby-telnet/src/components/telnetTab.component.ts b/tabby-telnet/src/components/telnetTab.component.ts index 96438693..2330c3d4 100644 --- a/tabby-telnet/src/components/telnetTab.component.ts +++ b/tabby-telnet/src/components/telnetTab.component.ts @@ -54,7 +54,7 @@ export class TelnetTabComponent extends BaseTerminalTabComponent { // Session was closed abruptly if (!this.reconnectOffered) { this.reconnectOffered = true - this.write('Press any key to reconnect\r\n') + this.write(this.translate.instant('Press any key to reconnect') + '\r\n') this.input$.pipe(first()).subscribe(() => { if (!this.session?.open && this.reconnectOffered) { this.reconnect() @@ -77,7 +77,7 @@ export class TelnetTabComponent extends BaseTerminalTabComponent { this.setSession(session) try { - this.startSpinner('Connecting') + this.startSpinner(this.translate.instant('Connecting')) this.attachSessionHandler(session.serviceMessage$, msg => { this.write(`\r${colors.black.bgWhite(' Telnet ')} ${msg}\r\n`) @@ -118,8 +118,11 @@ export class TelnetTabComponent extends BaseTerminalTabComponent { return (await this.platform.showMessageBox( { type: 'warning', - message: `Disconnect from ${this.profile?.options.host}?`, - buttons: ['Disconnect', 'Do not close'], + message: this.translate.instant('Disconnect from {host}?', this.profile?.options), + buttons: [ + this.translate.instant('Disconnect'), + this.translate.instant('Do not close'), + ], defaultId: 0, cancelId: 1, } diff --git a/tabby-telnet/src/hotkeys.ts b/tabby-telnet/src/hotkeys.ts index 9e2bb6be..4b287e9a 100644 --- a/tabby-telnet/src/hotkeys.ts +++ b/tabby-telnet/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,10 +7,12 @@ export class TelnetHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'restart-telnet-session', - name: 'Restart current Telnet session', + name: this.translate.instant('Restart current Telnet session'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-telnet/src/profiles.ts b/tabby-telnet/src/profiles.ts index 1455f076..1d5fc0db 100644 --- a/tabby-telnet/src/profiles.ts +++ b/tabby-telnet/src/profiles.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { ProfileProvider, NewTabParameters, PartialProfile } from 'tabby-core' +import { ProfileProvider, NewTabParameters, PartialProfile, TranslateService } from 'tabby-core' import { TelnetProfileSettingsComponent } from './components/telnetProfileSettings.component' import { TelnetTabComponent } from './components/telnetTab.component' import { TelnetProfile } from './session' @@ -7,7 +7,7 @@ import { TelnetProfile } from './session' @Injectable({ providedIn: 'root' }) export class TelnetProfilesService extends ProfileProvider { id = 'telnet' - name = 'Telnet' + name = this.translate.instant('Telnet') supportsQuickConnect = false settingsComponent = TelnetProfileSettingsComponent configDefaults = { @@ -22,12 +22,14 @@ export class TelnetProfilesService extends ProfileProvider { }, } + constructor (private translate: TranslateService) { super() } + async getBuiltinProfiles (): Promise[]> { return [ { id: `telnet:template`, type: 'telnet', - name: 'Telnet session', + name: this.translate.instant('Telnet session'), icon: 'fas fa-network-wired', options: { host: '', @@ -43,7 +45,7 @@ export class TelnetProfilesService extends ProfileProvider { { id: `socket:template`, type: 'telnet', - name: 'Raw socket connection', + name: this.translate.instant('Raw socket connection'), icon: 'fas fa-network-wired', options: { host: '', diff --git a/tabby-terminal/src/api/baseTerminalTab.component.ts b/tabby-terminal/src/api/baseTerminalTab.component.ts index 38d6f116..1bcc4326 100644 --- a/tabby-terminal/src/api/baseTerminalTab.component.ts +++ b/tabby-terminal/src/api/baseTerminalTab.component.ts @@ -3,7 +3,7 @@ import { Spinner } from 'cli-spinner' import colors from 'ansi-colors' import { NgZone, OnInit, OnDestroy, Injector, ViewChild, HostBinding, Input, ElementRef, InjectFlags } from '@angular/core' import { trigger, transition, style, animate, AnimationTriggerMetadata } from '@angular/animations' -import { AppService, ConfigService, BaseTabComponent, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent, SubscriptionContainer, MenuItemOptions, PlatformService, HostWindowService, ResettableTimeout } from 'tabby-core' +import { AppService, ConfigService, BaseTabComponent, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent, SubscriptionContainer, MenuItemOptions, PlatformService, HostWindowService, ResettableTimeout, TranslateService } from 'tabby-core' import { BaseSession } from '../session' import { TerminalFrontendService } from '../services/terminalFrontend.service' @@ -118,6 +118,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit protected decorators: TerminalDecorator[] = [] protected contextMenuProviders: TabContextMenuItemProvider[] protected hostWindow: HostWindowService + protected translate: TranslateService // Deps end protected logger: Logger @@ -186,9 +187,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit this.decorators = injector.get(TerminalDecorator, null, InjectFlags.Optional) as TerminalDecorator[] this.contextMenuProviders = injector.get(TabContextMenuItemProvider, null, InjectFlags.Optional) as TabContextMenuItemProvider[] this.hostWindow = injector.get(HostWindowService) + this.translate = injector.get(TranslateService) this.logger = this.log.create('baseTerminalTab') - this.setTitle('Terminal') + this.setTitle(this.translate.instant('Terminal')) this.subscribeUntilDestroyed(this.hotkeys.hotkey$, async hotkey => { if (!this.hasFocus) { @@ -199,7 +201,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit if (this.frontend?.getSelection()) { this.frontend.copySelection() this.frontend.clearSelection() - this.notifications.notice('Copied') + this.notifications.notice(this.translate.instant('Copied')) } else { this.forEachFocusedTerminalPane(tab => tab.sendInput('\x03')) } @@ -207,7 +209,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit case 'copy': this.frontend?.copySelection() this.frontend?.clearSelection() - this.notifications.notice('Copied') + this.notifications.notice(this.translate.instant('Copied')) break case 'paste': this.forEachFocusedTerminalPane(tab => tab.paste()) @@ -440,12 +442,15 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit data = data.trim() if (data.includes('\r') && this.config.store.terminal.warnOnMultilinePaste) { - const buttons = ['Paste', 'Cancel'] + const buttons = [ + this.translate.instant('Paste'), + this.translate.instant('Cancel'), + ] const result = (await this.platform.showMessageBox( { type: 'warning', detail: data, - message: `Paste multiple lines?`, + message: this.translate.instant(`Paste multiple lines?`), buttons, defaultId: 0, cancelId: 1, @@ -534,9 +539,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit } if (cwd) { this.platform.setClipboard({ text: cwd }) - this.notifications.notice('Copied') + this.notifications.notice(this.translate.instant('Copied')) } else { - this.notifications.error('Shell does not support current path detection') + this.notifications.error(this.translate.instant('Shell does not support current path detection')) } } @@ -734,7 +739,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit this.attachSessionHandler(this.session.oscProcessor.copyRequested$, content => { this.platform.setClipboard({ text: content }) - this.notifications.notice('Copied') + this.notifications.notice(this.translate.instant('Copied')) }) } diff --git a/tabby-terminal/src/components/appearanceSettingsTab.component.pug b/tabby-terminal/src/components/appearanceSettingsTab.component.pug index 215e1efd..4c0b046d 100644 --- a/tabby-terminal/src/components/appearanceSettingsTab.component.pug +++ b/tabby-terminal/src/components/appearanceSettingsTab.component.pug @@ -1,9 +1,9 @@ -h3.mb-3 Appearance +h3.mb-3(translate) Appearance .row .col-12.col-md-6 .form-line .header - .title Font + .title(translate) Font .input-group.w-75 input.form-control.w-75( @@ -22,7 +22,7 @@ h3.mb-3 Appearance .form-line .header - .title Enable font ligatures + .title(translate) Enable font ligatures toggle( [(ngModel)]='config.store.terminal.ligatures', (ngModelChange)='config.save()', @@ -34,7 +34,7 @@ h3.mb-3 Appearance .content-box .form-line .header - .title Terminal background + .title(translate) Terminal background .btn-group( [(ngModel)]='config.store.terminal.background', @@ -47,18 +47,18 @@ h3.mb-3 Appearance ngbButton, [value]='"theme"' ) - | From theme + span(translate) From theme label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"colorScheme"' ) - | From color scheme + span(translate) From color scheme .form-line .header - .title Cursor shape + .title(translate) Cursor shape .btn-group( [(ngModel)]='config.store.terminal.cursor', @@ -89,7 +89,7 @@ h3.mb-3 Appearance .form-line .header - .title Blink cursor + .title(translate) Blink cursor toggle( [(ngModel)]='config.store.terminal.cursorBlink', @@ -98,8 +98,8 @@ h3.mb-3 Appearance .form-line .header - .title Fallback font - .description A second font family used to display characters missing in the main font + .title(translate) Fallback font + .description(translate) A second font family used to display characters missing in the main font input.form-control( type='text', @@ -110,8 +110,8 @@ h3.mb-3 Appearance .form-line .header - .title Line padding - .description Additional space between lines + .title(translate) Line padding + .description(translate) Additional space between lines input.form-control( type='number', [(ngModel)]='config.store.terminal.linePadding', @@ -121,7 +121,7 @@ h3.mb-3 Appearance .form-line .header - .title Custom CSS + .title(translate) Custom CSS textarea.form-control.mb-5( [(ngModel)]='config.store.appearance.css', diff --git a/tabby-terminal/src/components/baseTerminalTab.component.pug b/tabby-terminal/src/components/baseTerminalTab.component.pug index 2ff8fc9b..5e5be81b 100644 --- a/tabby-terminal/src/components/baseTerminalTab.component.pug +++ b/tabby-terminal/src/components/baseTerminalTab.component.pug @@ -15,5 +15,5 @@ button.btn.btn-sm.btn-link.toolbar-pin-button( ) i.fas.fa-thumbtack(*ngIf='revealToolbar || pinToolbar') i.fas.fa-wrench.mr-3(*ngIf='!revealToolbar && !pinToolbar') - span(*ngIf='pinToolbar') Unpin - span(*ngIf='!pinToolbar && revealToolbar') Pin + span(*ngIf='pinToolbar', translate) Unpin + span(*ngIf='!pinToolbar && revealToolbar', translate) Pin diff --git a/tabby-terminal/src/components/colorSchemeSettingsTab.component.pug b/tabby-terminal/src/components/colorSchemeSettingsTab.component.pug index 210bff6c..e09161bd 100644 --- a/tabby-terminal/src/components/colorSchemeSettingsTab.component.pug +++ b/tabby-terminal/src/components/colorSchemeSettingsTab.component.pug @@ -1,5 +1,5 @@ .head - h3.mb-3 Current color scheme + h3.mb-3(translate) Current color scheme .d-flex.align-items-center(*ngIf='!editing') span {{getCurrentSchemeName()}} @@ -7,18 +7,18 @@ .btn-toolbar button.btn.btn-secondary((click)='editScheme()') i.fas.fa-pen - span Edit + span(translate) Edit .mr-1 button.btn.btn-danger( (click)='deleteScheme(config.store.terminal.colorScheme)', *ngIf='currentCustomScheme' ) i.fas.fa-trash - span Delete + span(translate) Delete div(*ngIf='editing') .form-group - label Name + label(translate) Name input.form-control(type='text', [(ngModel)]='config.store.terminal.colorScheme.name') .form-group @@ -60,11 +60,11 @@ .mr-auto button.btn.btn-primary((click)='saveScheme()') i.fas.fa-check - span Save + span(translate) Save .mr-1 button.btn.btn-secondary((click)='cancelEditing()') i.fas.fa-times - span Cancel + span(translate) Cancel hr.mt-3.mb-4 diff --git a/tabby-terminal/src/components/colorSchemeSettingsTab.component.ts b/tabby-terminal/src/components/colorSchemeSettingsTab.component.ts index 84974111..6cdd15b8 100644 --- a/tabby-terminal/src/components/colorSchemeSettingsTab.component.ts +++ b/tabby-terminal/src/components/colorSchemeSettingsTab.component.ts @@ -2,7 +2,7 @@ import deepEqual from 'deep-equal' import { Component, Inject, Input, ChangeDetectionStrategy, ChangeDetectorRef, HostBinding } from '@angular/core' -import { ConfigService, PlatformService } from 'tabby-core' +import { ConfigService, PlatformService, TranslateService } from 'tabby-core' import { TerminalColorSchemeProvider } from '../api/colorSchemeProvider' import { TerminalColorScheme } from '../api/interfaces' @@ -29,6 +29,7 @@ export class ColorSchemeSettingsTabComponent { @Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[], private changeDetector: ChangeDetectorRef, private platform: PlatformService, + private translate: TranslateService, public config: ConfigService, ) { } @@ -80,8 +81,11 @@ export class ColorSchemeSettingsTabComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: `Delete "${scheme.name}"?`, - buttons: ['Delete', 'Keep'], + message: this.translate.instant('Delete "{name}"?', scheme), + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Keep'), + ], defaultId: 1, cancelId: 1, } diff --git a/tabby-terminal/src/components/loginScriptsSettings.component.pug b/tabby-terminal/src/components/loginScriptsSettings.component.pug index b6518cc6..8505ddb7 100644 --- a/tabby-terminal/src/components/loginScriptsSettings.component.pug +++ b/tabby-terminal/src/components/loginScriptsSettings.component.pug @@ -21,24 +21,24 @@ div([sortablejs]='scripts') [class.active]='!script.isRegex', ) i.fas.fa-fw([class.fa-check]='!script.isRegex') - span Exact match + span(translate) Exact match a.dropdown-item( href='#', (click)='script.isRegex = true', [class.active]='script.isRegex', ) i.fas.fa-fw([class.fa-check]='script.isRegex') - span Regex + span(translate) Regex a.dropdown-item( href='#', (click)='script.optional = !script.optional', [class.active]='script.optional', ) i.fas.fa-fw([class.fa-check]='script.optional') - span Optional + span(translate) Optional button.btn.btn-link.btn-sm.hover-reveal((click)='deleteScript(script)') i.fas.fa-fw.fa-trash-alt button.btn.btn-secondary.mt-2((click)='addScript()') i.fas.fa-plus - span New item + span(translate) New item diff --git a/tabby-terminal/src/components/loginScriptsSettings.component.ts b/tabby-terminal/src/components/loginScriptsSettings.component.ts index 9736e7f9..8c376b48 100644 --- a/tabby-terminal/src/components/loginScriptsSettings.component.ts +++ b/tabby-terminal/src/components/loginScriptsSettings.component.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Component, Input } from '@angular/core' -import { PlatformService } from 'tabby-core' +import { PlatformService, TranslateService } from 'tabby-core' import { LoginScript, LoginScriptsOptions } from '../middleware/loginScriptProcessing' /** @hidden */ @@ -15,6 +15,7 @@ export class LoginScriptsSettingsComponent { constructor ( private platform: PlatformService, + private translate: TranslateService, ) { } ngOnInit () { @@ -25,9 +26,12 @@ export class LoginScriptsSettingsComponent { if ((await this.platform.showMessageBox( { type: 'warning', - message: 'Delete this script?', + message: this.translate.instant('Delete this script?'), detail: script.expect, - buttons: ['Delete', 'Keep'], + buttons: [ + this.translate.instant('Delete'), + this.translate.instant('Keep'), + ], defaultId: 0, cancelId: 1, } diff --git a/tabby-terminal/src/components/searchPanel.component.pug b/tabby-terminal/src/components/searchPanel.component.pug index 54a88156..c20538e3 100644 --- a/tabby-terminal/src/components/searchPanel.component.pug +++ b/tabby-terminal/src/components/searchPanel.component.pug @@ -6,7 +6,7 @@ input.search-input.form-control( (click)='$event.stopPropagation()', (keyup.enter)='findPrevious()', (keyup.esc)='close.emit()', - placeholder='Search...' + [placeholder]='"Search"|translate' ) button.btn.btn-link( diff --git a/tabby-terminal/src/components/searchPanel.component.ts b/tabby-terminal/src/components/searchPanel.component.ts index a8537740..a5aedbca 100644 --- a/tabby-terminal/src/components/searchPanel.component.ts +++ b/tabby-terminal/src/components/searchPanel.component.ts @@ -1,6 +1,6 @@ import { Component, Input, Output, EventEmitter } from '@angular/core' import { Frontend, SearchOptions } from '../frontends/frontend' -import { ConfigService, NotificationsService } from 'tabby-core' +import { ConfigService, NotificationsService, TranslateService } from 'tabby-core' @Component({ selector: 'search-panel', @@ -29,6 +29,7 @@ export class SearchPanelComponent { constructor ( private notifications: NotificationsService, + private translate: TranslateService, public config: ConfigService, ) { } @@ -43,7 +44,7 @@ export class SearchPanelComponent { } if (!this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })) { this.notFound = true - this.notifications.notice('Not found') + this.notifications.notice(this.translate.instant('Not found')) } } @@ -53,7 +54,7 @@ export class SearchPanelComponent { } if (!this.frontend.findPrevious(this.query, { ...this.options, incremental: incremental || undefined })) { this.notFound = true - this.notifications.notice('Not found') + this.notifications.notice(this.translate.instant('Not found')) } } diff --git a/tabby-terminal/src/components/streamProcessingSettings.component.pug b/tabby-terminal/src/components/streamProcessingSettings.component.pug index c64c93bb..17aa129f 100644 --- a/tabby-terminal/src/components/streamProcessingSettings.component.pug +++ b/tabby-terminal/src/components/streamProcessingSettings.component.pug @@ -1,6 +1,6 @@ .form-line .header - .title Input mode + .title(translate) Input mode .d-flex(ngbDropdown) button.btn.btn-secondary.btn-tab-bar( @@ -13,21 +13,21 @@ (click)='options.inputMode = mode.key', ngbDropdownItem ) - div {{mode.name}} - .text-muted {{mode.description}} + div {{mode.name|translate}} + .text-muted {{mode.description|translate}} .form-line .header - .title Input newlines + .title(translate) Input newlines select.form-control( [(ngModel)]='options.inputNewlines', ) - option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}} + option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name|translate}} .form-line .header - .title Output mode + .title(translate) Output mode .d-flex(ngbDropdown) button.btn.btn-secondary.btn-tab-bar( @@ -40,14 +40,14 @@ (click)='options.outputMode = mode.key', ngbDropdownItem ) - div {{mode.name}} - .text-muted {{mode.description}} + div {{mode.name|translate}} + .text-muted {{mode.description|translate}} .form-line .header - .title Output newlines + .title(translate) Output newlines select.form-control( [(ngModel)]='options.outputNewlines', ) - option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}} + option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name|translate}} diff --git a/tabby-terminal/src/components/streamProcessingSettings.component.ts b/tabby-terminal/src/components/streamProcessingSettings.component.ts index 5eddcd6b..f04dcabe 100644 --- a/tabby-terminal/src/components/streamProcessingSettings.component.ts +++ b/tabby-terminal/src/components/streamProcessingSettings.component.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' import { Component, Input } from '@angular/core' import { StreamProcessingOptions } from '../middleware/streamProcessing' @@ -11,21 +12,45 @@ export class StreamProcessingSettingsComponent { @Input() options: StreamProcessingOptions inputModes = [ - { key: null, name: 'Normal', description: 'Input is sent as you type' }, - { key: 'local-echo', name: 'Local echo', description: 'Immediately echoes your input locally' }, - { key: 'readline', name: 'Line by line', description: 'Line editor, input is sent after you press Enter' }, - { key: 'readline-hex', name: 'Hexadecimal', description: 'Send bytes by typing in hex values' }, + { + key: null, + name: _('Normal'), + description: _('Input is sent as you type'), + }, + { + key: 'local-echo', + name: _('Local echo'), + description: _('Immediately echoes your input locally'), + }, + { + key: 'readline', + name: _('Line by line'), + description: _('Line editor, input is sent after you press Enter'), + }, + { + key: 'readline-hex', + name: _('Hexadecimal'), + description: _('Send bytes by typing in hex values'), + }, ] outputModes = [ - { key: null, name: 'Normal', description: 'Output is shown as it is received' }, - { key: 'hex', name: 'Hexadecimal', description: 'Output is shown as a hexdump' }, + { + key: null, + name: _('Normal'), + description: _('Output is shown as it is received'), + }, + { + key: 'hex', + name: _('Hexadecimal'), + description: _('Output is shown as a hexdump'), + }, ] newlineModes = [ - { key: null, name: 'Keep' }, - { key: 'strip', name: 'Strip' }, - { key: 'cr', name: 'Force CR' }, - { key: 'lf', name: 'Force LF' }, - { key: 'crlf', name: 'Force CRLF' }, + { key: null, name: _('Keep') }, + { key: 'strip', name: _('Strip') }, + { key: 'cr', name: _('Force CR') }, + { key: 'lf', name: _('Force LF') }, + { key: 'crlf', name: _('Force CRLF') }, ] getInputModeName (key) { diff --git a/tabby-terminal/src/components/terminalSettingsTab.component.pug b/tabby-terminal/src/components/terminalSettingsTab.component.pug index 53b54baf..63b826a7 100644 --- a/tabby-terminal/src/components/terminalSettingsTab.component.pug +++ b/tabby-terminal/src/components/terminalSettingsTab.component.pug @@ -1,10 +1,10 @@ div - h3.mb-3 Rendering + h3.mb-3(translate) Rendering .form-line(*ngIf='hostApp.platform !== Platform.Web') .header - .title Frontend - .description Switches terminal frontend implementation (experimental) + .title(translate) Frontend + .description(translate) Switches terminal frontend implementation (experimental) select.form-control( [(ngModel)]='config.store.terminal.frontend', @@ -15,8 +15,8 @@ div .form-line .header - .title Scrollback - .description Number of lines kept in the buffer + .title(translate) Scrollback + .description(translate) Number of lines kept in the buffer input.form-control( type='number', [(ngModel)]='config.store.terminal.scrollbackLines', @@ -28,8 +28,8 @@ div.mt-4 .form-line .header - .title Use {{altKeyName}} as the Meta key - .description Lets the shell handle Meta key instead of OS + .title(translate, [translateParams]='{altKeyName: altKeyName}') Use {altKeyName} as the Meta key + .description(translate) Lets the shell handle Meta key instead of OS toggle( [(ngModel)]='config.store.terminal.altIsMeta', (ngModelChange)='config.save()', @@ -37,8 +37,8 @@ div.mt-4 .form-line .header - .title Scroll on input - .description Scrolls the terminal to the bottom on user input + .title(translate) Scroll on input + .description(translate) Scrolls the terminal to the bottom on user input toggle( [(ngModel)]='config.store.terminal.scrollOnInput', (ngModelChange)='config.save()', @@ -49,8 +49,8 @@ div.mt-4 .form-line .header - .title Right click - .description(*ngIf='config.store.terminal.rightClick == "paste"') Long-click for context menu + .title(translate) Right click + .description(*ngIf='config.store.terminal.rightClick == "paste"', translate) Long-click for context menu .btn-group( [(ngModel)]='config.store.terminal.rightClick', (ngModelChange)='config.save()', @@ -62,25 +62,25 @@ div.mt-4 ngbButton, value='off' ) - | Off + span(translate) Off label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, value='menu' ) - | Context menu + span(translate) Context menu label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, value='paste' ) - | Paste + span(translate) Paste .form-line .header - .title Paste on middle-click + .title(translate) Paste on middle-click toggle( [(ngModel)]='config.store.terminal.pasteOnMiddleClick', @@ -89,8 +89,8 @@ div.mt-4 .form-line .header - .title Word separators - .description Double-click selection will stop at these characters + .title(translate) Word separators + .description(translate) Double-click selection will stop at these characters input.form-control( type='text', placeholder=' ()[]{}\'"', @@ -100,25 +100,25 @@ div.mt-4 .form-line .header - .title Require a key to click links - .description When enabled, links are only clickable while holding this key + .title(translate) Require a key to click links + .description(translate) When enabled, links are only clickable while holding this key select.form-control( [(ngModel)]='config.store.clickableLinks.modifier', (ngModelChange)='config.save()', ) - option([value]='null') None + option([value]='null', translate) No modifier option(value='ctrlKey') Ctrl option(value='altKey') {{altKeyName}} option(value='shiftKey') Shift option(value='metaKey') {{metaKeyName}} -div.mt-4 - h3 Clipboard +.mt-4 + h3(translate) Clipboard .form-line .header - .title Copy on select + .title(translate) Copy on select toggle( [(ngModel)]='config.store.terminal.copyOnSelect', (ngModelChange)='config.save()', @@ -126,8 +126,8 @@ div.mt-4 .form-line .header - .title Bracketed paste (requires shell support) - .description Prevents accidental execution of pasted commands + .title(translate) Bracketed paste (requires shell support) + .description(translate) Prevents accidental execution of pasted commands toggle( [(ngModel)]='config.store.terminal.bracketedPaste', (ngModelChange)='config.save()', @@ -135,8 +135,8 @@ div.mt-4 .form-line .header - .title Warn on multi-line paste - .description Show a confirmation box when pasting multiple lines + .title(translate) Warn on multi-line paste + .description(translate) Show a confirmation box when pasting multiple lines toggle( [(ngModel)]='config.store.terminal.warnOnMultilinePaste', (ngModelChange)='config.save()', @@ -147,7 +147,7 @@ div.mt-4 .form-line .header - .title Terminal bell + .title(translate) Terminal bell .btn-group( [(ngModel)]='config.store.terminal.bell', (ngModelChange)='config.save()', @@ -159,32 +159,32 @@ div.mt-4 ngbButton, [value]='"off"' ) - | Off + span(translate) Off label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"visual"' ) - | Visual + span(translate) Visual label.btn.btn-secondary(ngbButtonLabel) input( type='radio', ngbButton, [value]='"audible"' ) - | Audible + span(translate) Audible .alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.bell != "audible" && (config.store.terminal.profile || "").startsWith("wsl")') - .mr-auto WSL terminal bell can only be muted via Volume Mixer - button.btn.btn-secondary((click)='openWSLVolumeMixer()') Show Mixer + .mr-auto(translate) WSL terminal bell can only be muted via Volume Mixer + button.btn.btn-secondary((click)='openWSLVolumeMixer()', translate) Show Mixer -div.mt-4 - h3 Startup +.mt-4 + h3(translate) Startup .form-line(*ngIf='hostApp.platform !== Platform.Web') .header - .title Auto-open a terminal on app start + .title(translate) Auto-open a terminal on app start toggle( [(ngModel)]='config.store.terminal.autoOpen', @@ -193,7 +193,7 @@ div.mt-4 .form-line .header - .title Restore terminal tabs on app start + .title(translate) Restore terminal tabs on app start toggle( [(ngModel)]='config.store.recoverTabs', @@ -205,8 +205,8 @@ div.mt-4(*ngIf='hostApp.platform === Platform.Windows') .form-line .header - .title Set Tabby as %COMSPEC% - .description Allows opening .bat files in tabs, but breaks some shells + .title(translate) Set Tabby as %COMSPEC% + .description(translate) Allows opening .bat files in tabs, but breaks some shells toggle( [(ngModel)]='config.store.terminal.setComSpec', (ngModelChange)='config.save()', diff --git a/tabby-terminal/src/hotkeys.ts b/tabby-terminal/src/hotkeys.ts index dcaac5fc..f315567b 100644 --- a/tabby-terminal/src/hotkeys.ts +++ b/tabby-terminal/src/hotkeys.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { HotkeyDescription, HotkeyProvider } from 'tabby-core' +import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core' /** @hidden */ @Injectable() @@ -7,70 +7,72 @@ export class TerminalHotkeyProvider extends HotkeyProvider { hotkeys: HotkeyDescription[] = [ { id: 'copy', - name: 'Copy to clipboard', + name: this.translate.instant('Copy to clipboard'), }, { id: 'paste', - name: 'Paste from clipboard', + name: this.translate.instant('Paste from clipboard'), }, { id: 'home', - name: 'Beginning of the line', + name: this.translate.instant('Beginning of the line'), }, { id: 'end', - name: 'End of the line', + name: this.translate.instant('End of the line'), }, { id: 'previous-word', - name: 'Jump to previous word', + name: this.translate.instant('Jump to previous word'), }, { id: 'next-word', - name: 'Jump to next word', + name: this.translate.instant('Jump to next word'), }, { id: 'delete-previous-word', - name: 'Delete previous word', + name: this.translate.instant('Delete previous word'), }, { id: 'delete-next-word', - name: 'Delete next word', + name: this.translate.instant('Delete next word'), }, { id: 'clear', - name: 'Clear terminal', + name: this.translate.instant('Clear terminal'), }, { id: 'zoom-in', - name: 'Zoom in', + name: this.translate.instant('Zoom in'), }, { id: 'zoom-out', - name: 'Zoom out', + name: this.translate.instant('Zoom out'), }, { id: 'reset-zoom', - name: 'Reset zoom', + name: this.translate.instant('Reset zoom'), }, { id: 'ctrl-c', - name: 'Intelligent Ctrl-C (copy/abort)', + name: this.translate.instant('Intelligent Ctrl-C (copy/abort)'), }, { id: 'copy-current-path', - name: 'Copy current path', + name: this.translate.instant('Copy current path'), }, { id: 'search', - name: 'Search', + name: this.translate.instant('Search'), }, { id: 'pane-focus-all', - name: 'Focus all panes at once (broadcast)', + name: this.translate.instant('Focus all panes at once (broadcast)'), }, ] + constructor (private translate: TranslateService) { super() } + async provide (): Promise { return this.hotkeys } diff --git a/tabby-terminal/src/settings.ts b/tabby-terminal/src/settings.ts index a34c3418..35b807e0 100644 --- a/tabby-terminal/src/settings.ts +++ b/tabby-terminal/src/settings.ts @@ -4,15 +4,18 @@ import { SettingsTabProvider } from 'tabby-settings' import { AppearanceSettingsTabComponent } from './components/appearanceSettingsTab.component' import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.component' import { ColorSchemeSettingsTabComponent } from './components/colorSchemeSettingsTab.component' +import { TranslateService } from 'tabby-core' /** @hidden */ @Injectable() export class AppearanceSettingsTabProvider extends SettingsTabProvider { id = 'terminal-appearance' icon = 'swatchbook' - title = 'Appearance' + title = this.translate.instant('Appearance') prioritized = true + constructor (private translate: TranslateService) { super() } + getComponentType (): any { return AppearanceSettingsTabComponent } @@ -23,7 +26,9 @@ export class AppearanceSettingsTabProvider extends SettingsTabProvider { export class ColorSchemeSettingsTabProvider extends SettingsTabProvider { id = 'terminal-color-scheme' icon = 'palette' - title = 'Color scheme' + title = this.translate.instant('Color scheme') + + constructor (private translate: TranslateService) { super() } getComponentType (): any { return ColorSchemeSettingsTabComponent @@ -35,9 +40,11 @@ export class ColorSchemeSettingsTabProvider extends SettingsTabProvider { export class TerminalSettingsTabProvider extends SettingsTabProvider { id = 'terminal' icon = 'terminal' - title = 'Terminal' + title = this.translate.instant('Terminal') prioritized = true + constructor (private translate: TranslateService) { super() } + getComponentType (): any { return TerminalSettingsTabComponent } diff --git a/tabby-terminal/src/tabContextMenu.ts b/tabby-terminal/src/tabContextMenu.ts index 92c3c6fb..ac4ab296 100644 --- a/tabby-terminal/src/tabContextMenu.ts +++ b/tabby-terminal/src/tabContextMenu.ts @@ -1,5 +1,5 @@ import { Injectable, Optional, Inject } from '@angular/core' -import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, NotificationsService, MenuItemOptions } from 'tabby-core' +import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, NotificationsService, MenuItemOptions, TranslateService } from 'tabby-core' import { BaseTerminalTabComponent } from './api/baseTerminalTab.component' import { TerminalContextMenuItemProvider } from './api/contextMenuProvider' @@ -10,6 +10,7 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider { constructor ( private notifications: NotificationsService, + private translate: TranslateService, ) { super() } @@ -21,16 +22,16 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider { if (tab instanceof BaseTerminalTabComponent) { return [ { - label: 'Copy', + label: this.translate.instant('Copy'), click: (): void => { setTimeout(() => { tab.frontend?.copySelection() - this.notifications.notice('Copied') + this.notifications.notice(this.translate.instant('Copied')) }) }, }, { - label: 'Paste', + label: this.translate.instant('Paste'), click: () => tab.paste(), }, ] @@ -44,10 +45,12 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider { export class MiscContextMenu extends TabContextMenuItemProvider { weight = 1 + constructor (private translate: TranslateService) { super() } + async getItems (tab: BaseTabComponent): Promise { if (tab instanceof BaseTerminalTabComponent && tab.session?.supportsWorkingDirectory()) { return [{ - label: 'Copy current path', + label: this.translate.instant('Copy current path'), click: () => tab.copyCurrentPath(), }] } diff --git a/tabby-web/src/services/hostWindow.service.ts b/tabby-web/src/services/hostWindow.service.ts index cfa69c23..079e76ab 100644 --- a/tabby-web/src/services/hostWindow.service.ts +++ b/tabby-web/src/services/hostWindow.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { ConfigService, HostWindowService } from 'tabby-core' +import { ConfigService, HostWindowService, TranslateService } from 'tabby-core' @Injectable({ providedIn: 'root' }) export class WebHostWindow extends HostWindowService { @@ -7,6 +7,7 @@ export class WebHostWindow extends HostWindowService { constructor ( config: ConfigService, + translate: TranslateService, ) { super() this.windowShown.next() @@ -15,7 +16,7 @@ export class WebHostWindow extends HostWindowService { const unloadHandler = (event) => { if (config.store.web.preventAccidentalTabClosure) { event.preventDefault() - event.returnValue = 'Are you sure you want to close Tabby? You can disable this prompt in Settings -> Window.' + event.returnValue = translate.instant('Are you sure you want to close Tabby? You can disable this prompt in Settings -> Window.') } else { window.removeEventListener('beforeunload', unloadHandler) } diff --git a/webpack.plugin.config.js b/webpack.plugin.config.js index 78ca1b8f..4ddcc918 100644 --- a/webpack.plugin.config.js +++ b/webpack.plugin.config.js @@ -47,6 +47,7 @@ module.exports = options => { alias: options.alias ?? {}, modules: ['.', 'src', 'node_modules', '../app/node_modules', '../node_modules'].map(x => path.join(options.dirname, x)), extensions: ['.ts', '.js'], + mainFields: ['esm2015', 'browser', 'module', 'main'], }, ignoreWarnings: [/Failed to parse source map/], module: { @@ -89,6 +90,13 @@ module.exports = options => { test: /\.(ttf|eot|otf|woff|woff2|ogg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, type: 'asset', }, + { + test: /\.po$/, + use: [ + { loader: 'json-loader' }, + { loader: 'po-gettext-loader' }, + ], + }, ], }, externals: [ diff --git a/yarn.lock b/yarn.lock index 252f1b06..1e59af51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,6 +80,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "@babel/highlight@^7.10.4": version "7.13.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" @@ -99,19 +104,41 @@ js-tokens "^4.0.0" "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" - integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== "@babel/types@^7.6.1", "@babel/types@^7.9.6": - version "7.12.12" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" - integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@biesbjerg/ngx-translate-extract-marker@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@biesbjerg/ngx-translate-extract-marker/-/ngx-translate-extract-marker-1.0.0.tgz#3c50b5305fb2ffe4826c1473e25e6f746bb31916" + integrity sha512-GlCBQKmFE+b+qfIO0aGvuRc4LJVSfK27K2QQFXZLP55/w28iiq/q2CnBS8ya+4l+hapm7U3QPtFoZu9lmbUuew== + dependencies: + tslib "^1.9.0" + +"@biesbjerg/ngx-translate-extract@^7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@biesbjerg/ngx-translate-extract/-/ngx-translate-extract-7.0.4.tgz#98190aa798dfe78a9f33904256891e76634fd52c" + integrity sha512-33hR94Fu26LK7Z+ImW2IdZiHfOcAzyIs1CdkUXg/536z2MqxBYqPoI9Ghsk6RTEfnsGa65wMgOcDXn7Ilhp8ew== + dependencies: + "@phenomnomnominal/tsquery" "^4.1.1" + boxen "^5.0.1" + colorette "^1.2.2" + flat "^5.0.2" + gettext-parser "^4.0.4" + glob "^7.1.6" + mkdirp "^1.0.4" + path "^0.12.7" + terminal-link "^2.1.1" + yargs "^16.2.0" + "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz" @@ -259,6 +286,13 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@phenomnomnominal/tsquery@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@phenomnomnominal/tsquery/-/tsquery-4.1.1.tgz#42971b83590e9d853d024ddb04a18085a36518df" + integrity sha512-jjMmK1tnZbm1Jq5a7fBliM4gQwjxMU7TFoRNwIyzwlO+eHPRCFv/Nv+H/Gi1jc3WR7QURG8D5d0Tn12YGrUqBQ== + dependencies: + esquery "^1.0.1" + "@polka/url@^1.0.0-next.9": version "1.0.0-next.12" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.12.tgz#431ec342a7195622f86688bbda82e3166ce8cb28" @@ -839,13 +873,6 @@ abbrev@~1.1.0: resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz" integrity sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8= -acorn-globals@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" - integrity sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8= - dependencies: - acorn "^4.0.4" - acorn-import-assertions@^1.7.6: version "1.7.6" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78" @@ -861,12 +888,7 @@ acorn-walk@^8.0.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.0.2.tgz#d4632bfc63fd93d0f15fd05ea0e984ffd3f5a8c3" integrity sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A== -acorn@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - -acorn@^4.0.1, acorn@^4.0.4, acorn@~4.0.2: +acorn@^4.0.1, acorn@~4.0.2: version "4.0.13" resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz" integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c= @@ -952,15 +974,6 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz" @@ -980,6 +993,13 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -1387,6 +1407,20 @@ boxen@^5.0.0: widest-line "^3.1.0" wrap-ansi "^7.0.0" +boxen@^5.0.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1610,11 +1644,6 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= - camelcase@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" @@ -1650,17 +1679,9 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - chalk@^1.0.0, chalk@^1.1.1: version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" @@ -1735,7 +1756,7 @@ ci-info@^3.1.1: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== -clean-css@^4.1.11, clean-css@^4.2.3: +clean-css@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz" integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== @@ -1777,15 +1798,6 @@ cli-truncate@^1.1.0: slice-ansi "^1.0.0" string-width "^2.0.0" -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - cliui@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz" @@ -1923,7 +1935,7 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.20.0, commander@^2.9.0: +commander@^2.20.0, commander@^2.8.1, commander@^2.9.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2033,7 +2045,7 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constantinople@^3.0.1, constantinople@^3.1.2: +constantinople@^3.0.1: version "3.1.2" resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647" integrity sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw== @@ -2051,6 +2063,11 @@ constantinople@^4.0.1: "@babel/parser" "^7.6.0" "@babel/types" "^7.6.1" +content-type@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + cookie@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" @@ -2249,7 +2266,7 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -2691,12 +2708,12 @@ encodeurl@^1.0.2: encoding@^0.1.11: version "0.1.12" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= dependencies: iconv-lite "~0.4.13" -encoding@^0.1.12: +encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -2951,7 +2968,7 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: +esquery@^1.0.1, esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== @@ -3180,6 +3197,11 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flatted@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" @@ -3480,6 +3502,16 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +gettext-parser@^4.0.3, gettext-parser@^4.0.4: + version "4.2.0" + resolved "https://registry.yarnpkg.com/gettext-parser/-/gettext-parser-4.2.0.tgz#9327140f76b122d44f0e8cb9338fd855667d9434" + integrity sha512-aMgPyjC9W5Mz9tbFU8DcQ7GYMXoFWq633kaWGt4imlcpBWzDIWk7HY7nCSZTCJxyjRaLq9L/NEjMKkZ9gR630Q== + dependencies: + content-type "^1.0.4" + encoding "^0.1.13" + readable-stream "^3.6.0" + safe-buffer "^5.2.1" + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -3999,6 +4031,11 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" @@ -4080,11 +4117,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz" @@ -4125,6 +4157,13 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-core-module@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -4512,9 +4551,9 @@ json-buffer@3.0.1: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-loader@0.5.7: +json-loader@^0.5.7: version "0.5.7" - resolved "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w== json-parse-better-errors@^1.0.2: @@ -4658,13 +4697,6 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" @@ -4696,11 +4728,6 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= - lazy-property@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz" @@ -4857,7 +4884,7 @@ lodash.without@~4.4.0: resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz" integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@~4.17.10: +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.4, lodash@~4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4869,11 +4896,6 @@ log-symbols@^4.0.0: dependencies: chalk "^4.0.0" -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz" @@ -6119,7 +6141,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -6138,6 +6160,14 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= + dependencies: + process "^0.11.1" + util "^0.10.3" + pend@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" @@ -6203,6 +6233,13 @@ plist@^3.0.1: xmlbuilder "^9.0.7" xmldom "0.1.x" +po-gettext-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/po-gettext-loader/-/po-gettext-loader-1.0.0.tgz#7deeed3b6c9b83cb682930afdd36a57829c40a03" + integrity sha512-pNu6gPzsUQDnD2SJIMZYhf8005ZBf9Ypw0+dmiJYksd6reKMGN02+ICJRFiqk/yrJEHTIugLyJCqgDpu9eqP+A== + dependencies: + gettext-parser "^4.0.3" + postcss-modules-extract-imports@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" @@ -6281,6 +6318,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.1: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + progress-stream@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz" @@ -6361,7 +6403,7 @@ psl@^1.1.28: resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -pug-attrs@^2.0.3, pug-attrs@^2.0.4: +pug-attrs@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-2.0.4.tgz#b2f44c439e4eb4ad5d4ef25cac20d18ad28cc336" integrity sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ== @@ -6379,19 +6421,15 @@ pug-attrs@^3.0.0: js-stringify "^1.0.2" pug-runtime "^3.0.0" -pug-code-gen@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-2.0.3.tgz#122eb9ada9b5bf601705fe15aaa0a7d26bc134ab" - integrity sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA== +pug-cli@^1.0.0-alpha6: + version "1.0.0-alpha6" + resolved "https://registry.yarnpkg.com/pug-cli/-/pug-cli-1.0.0-alpha6.tgz#1ca539ea4ac0ebb69ce4aae84aeed5d64ffe6501" + integrity sha1-HKU56krA67ac5KroSu7V1k/+ZQE= dependencies: - constantinople "^3.1.2" - doctypes "^1.1.0" - js-stringify "^1.0.1" - pug-attrs "^2.0.4" - pug-error "^1.3.3" - pug-runtime "^2.0.5" - void-elements "^2.0.1" - with "^5.0.0" + chalk "^1.0.0" + commander "^2.8.1" + mkdirp "^0.5.1" + pug "^2.0.0-alpha7" pug-code-gen@^3.0.2: version "3.0.2" @@ -6417,19 +6455,6 @@ pug-error@^2.0.0: resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== -pug-filters@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz" - integrity sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg== - dependencies: - clean-css "^4.1.11" - constantinople "^3.0.1" - jstransformer "1.0.0" - pug-error "^1.3.3" - pug-walk "^1.1.8" - resolve "^1.1.6" - uglify-js "^2.6.1" - pug-filters@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" @@ -6449,7 +6474,7 @@ pug-html-loader@1.1.5: loader-utils "^0.2.17" pug "^2.0.0-rc.2" -pug-lexer@^4.0.0, pug-lexer@^4.1.0: +pug-lexer@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz" integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA== @@ -6467,14 +6492,6 @@ pug-lexer@^5.0.1: is-expression "^4.0.0" pug-error "^2.0.0" -pug-linker@^3.0.6: - version "3.0.6" - resolved "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz" - integrity sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg== - dependencies: - pug-error "^1.3.3" - pug-walk "^1.1.8" - pug-linker@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" @@ -6502,14 +6519,6 @@ pug-lint@^2.6.0: strip-json-comments "^2.0.1" void-elements "^2.0.1" -pug-load@^2.0.12: - version "2.0.12" - resolved "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz" - integrity sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg== - dependencies: - object-assign "^4.1.0" - pug-walk "^1.1.8" - pug-load@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" @@ -6527,14 +6536,6 @@ pug-loader@^2.4.0: pug-walk "^1.0.0" resolve "^1.1.7" -pug-parser@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz" - integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA== - dependencies: - pug-error "^1.3.3" - token-stream "0.0.1" - pug-parser@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" @@ -6561,13 +6562,6 @@ pug-static-loader@2.0.0: joi "^10.6.0" pug "^2.0.0-rc.2" -pug-strip-comments@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz" - integrity sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw== - dependencies: - pug-error "^1.3.3" - pug-strip-comments@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" @@ -6575,7 +6569,7 @@ pug-strip-comments@^2.0.0: dependencies: pug-error "^2.0.0" -pug-walk@^1.0.0, pug-walk@^1.1.8: +pug-walk@^1.0.0: version "1.1.8" resolved "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz" integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA== @@ -6585,21 +6579,7 @@ pug-walk@^2.0.0: resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== -pug@^2.0.0-rc.2: - version "2.0.4" - resolved "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz" - integrity sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw== - dependencies: - pug-code-gen "^2.0.2" - pug-filters "^3.1.1" - pug-lexer "^4.1.0" - pug-linker "^3.0.6" - pug-load "^2.0.12" - pug-parser "^5.0.1" - pug-runtime "^2.0.5" - pug-strip-comments "^1.0.4" - -pug@^3.0.2: +pug@3, pug@^2.0.0-alpha7, pug@^2.0.0-rc.2, pug@^3: version "3.0.2" resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw== @@ -6926,11 +6906,6 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - repeating@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" @@ -7034,7 +7009,7 @@ resolve-from@^5.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.15.1, resolve@^1.17.0, resolve@^1.9.0: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.17.0, resolve@^1.9.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -7042,6 +7017,15 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.15.1, resolve@^1.17. is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^1.15.1: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" @@ -7079,13 +7063,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= - dependencies: - align-text "^0.1.1" - rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" @@ -7133,7 +7110,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -7498,11 +7475,6 @@ source-map@^0.7.1, source-map@~0.7.2: resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - source-sans-pro@3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/source-sans-pro/-/source-sans-pro-3.6.0.tgz" @@ -7666,7 +7638,7 @@ string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.3: +string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7822,7 +7794,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -7836,6 +7808,19 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + svg-inline-loader@^0.8.2: version "0.8.2" resolved "https://registry.npmjs.org/svg-inline-loader/-/svg-inline-loader-0.8.2.tgz" @@ -7928,6 +7913,14 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" +terminal-link@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + terser-webpack-plugin@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.3.tgz#30033e955ca28b55664f1e4b30a1347e61aa23af" @@ -8061,11 +8054,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -token-stream@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz" - integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo= - token-stream@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" @@ -8188,6 +8176,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -8226,21 +8219,6 @@ typescript@^4.3.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== -uglify-js@^2.6.1: - version "2.8.29" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz" - integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= - uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz" @@ -8402,6 +8380,13 @@ util-extend@^1.0.1: resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz" integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + utils-decorators@^1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/utils-decorators/-/utils-decorators-1.10.4.tgz#df3482fdddf127ca6db7ac58e0d3a19c99678bf1" @@ -8651,19 +8636,6 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= - -with@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe" - integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4= - dependencies: - acorn "^3.1.0" - acorn-globals "^3.0.0" - with@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" @@ -8679,11 +8651,6 @@ word-wrap@^1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= - worker-farm@~1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/worker-farm/-/worker-farm-1.3.1.tgz" @@ -8906,6 +8873,19 @@ yargs@^15.0.1: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^17.0.1: version "17.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.0.tgz#0cd9827a0572c9a1795361c4d1530e53ada168cf" @@ -8932,16 +8912,6 @@ yargs@^17.2.1: y18n "^5.0.5" yargs-parser "^21.0.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" -- GitLab