mirror of
https://github.com/Eugeny/tabby.git
synced 2025-10-04 22:14:55 +00:00
Translation infrastructure
This commit is contained in:
@@ -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<any>(TerminalDecorator, null, InjectFlags.Optional) as TerminalDecorator[]
|
||||
this.contextMenuProviders = injector.get<any>(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'))
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -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',
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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(
|
||||
|
@@ -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'))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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}}
|
||||
|
@@ -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) {
|
||||
|
@@ -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()',
|
||||
|
@@ -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<HotkeyDescription[]> {
|
||||
return this.hotkeys
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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<MenuItemOptions[]> {
|
||||
if (tab instanceof BaseTerminalTabComponent && tab.session?.supportsWorkingDirectory()) {
|
||||
return [{
|
||||
label: 'Copy current path',
|
||||
label: this.translate.instant('Copy current path'),
|
||||
click: () => tab.copyCurrentPath(),
|
||||
}]
|
||||
}
|
||||
|
Reference in New Issue
Block a user