mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-01 23:16:59 +00:00
Compare commits
1 Commits
v1.0.178
...
localizati
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4d6866ac75 |
@@ -17,12 +17,15 @@
|
|||||||
"author": "Eugene Pankov",
|
"author": "Eugene Pankov",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@ngx-translate/core": "^14.0.0",
|
||||||
"bootstrap": "^4.1.3",
|
"bootstrap": "^4.1.3",
|
||||||
"deepmerge": "^4.1.1",
|
"deepmerge": "^4.1.1",
|
||||||
"js-yaml": "^4.0.0",
|
"js-yaml": "^4.0.0",
|
||||||
|
"messageformat": "^2.3.0",
|
||||||
"mixpanel": "^0.13.0",
|
"mixpanel": "^0.13.0",
|
||||||
"ngx-filesize": "^2.0.16",
|
"ngx-filesize": "^2.0.16",
|
||||||
"ngx-perfect-scrollbar": "^10.1.0",
|
"ngx-perfect-scrollbar": "^10.1.0",
|
||||||
|
"ngx-translate-messageformat-compiler": "^4.11.0",
|
||||||
"readable-stream": "3.6.0",
|
"readable-stream": "3.6.0",
|
||||||
"uuid": "^8.0.0"
|
"uuid": "^8.0.0"
|
||||||
},
|
},
|
||||||
|
@@ -35,4 +35,5 @@ export { TabsService, NewTabParameters, TabComponentType } from '../services/tab
|
|||||||
export { UpdaterService } from '../services/updater.service'
|
export { UpdaterService } from '../services/updater.service'
|
||||||
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
||||||
export { FileProvidersService } from '../services/fileProviders.service'
|
export { FileProvidersService } from '../services/fileProviders.service'
|
||||||
|
export { LocaleService } from '../services/locale.service'
|
||||||
export * from '../utils'
|
export * from '../utils'
|
||||||
|
@@ -38,3 +38,4 @@ enableExperimentalFeatures: false
|
|||||||
pluginBlacklist: []
|
pluginBlacklist: []
|
||||||
hacks:
|
hacks:
|
||||||
disableGPU: false
|
disableGPU: false
|
||||||
|
language: en
|
||||||
|
@@ -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 { BrowserModule } from '@angular/platform-browser'
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
@@ -7,6 +7,8 @@ import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-sc
|
|||||||
import { NgxFilesizeModule } from 'ngx-filesize'
|
import { NgxFilesizeModule } from 'ngx-filesize'
|
||||||
import { SortablejsModule } from 'ngx-sortablejs'
|
import { SortablejsModule } from 'ngx-sortablejs'
|
||||||
import { DragDropModule } from '@angular/cdk/drag-drop'
|
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 { AppRootComponent } from './components/appRoot.component'
|
||||||
import { CheckboxComponent } from './components/checkbox.component'
|
import { CheckboxComponent } from './components/checkbox.component'
|
||||||
@@ -40,6 +42,7 @@ import { AppService } from './services/app.service'
|
|||||||
import { ConfigService } from './services/config.service'
|
import { ConfigService } from './services/config.service'
|
||||||
import { VaultFileProvider } from './services/vault.service'
|
import { VaultFileProvider } from './services/vault.service'
|
||||||
import { HotkeysService } from './services/hotkeys.service'
|
import { HotkeysService } from './services/hotkeys.service'
|
||||||
|
import { LocaleService, TranslateServiceWrapper } from './services/locale.service'
|
||||||
|
|
||||||
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
|
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
|
||||||
import { CoreConfigProvider } from './config'
|
import { CoreConfigProvider } from './config'
|
||||||
@@ -51,6 +54,10 @@ import { SplitLayoutProfilesService } from './profiles'
|
|||||||
|
|
||||||
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
||||||
|
|
||||||
|
export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler {
|
||||||
|
return new TranslateMessageFormatCompiler()
|
||||||
|
}
|
||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||||
{ provide: Theme, useClass: StandardTheme, multi: true },
|
{ provide: Theme, useClass: StandardTheme, multi: true },
|
||||||
@@ -68,6 +75,19 @@ const PROVIDERS = [
|
|||||||
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
||||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||||
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, 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 */
|
/** @hidden */
|
||||||
@@ -81,6 +101,7 @@ const PROVIDERS = [
|
|||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
DragDropModule,
|
DragDropModule,
|
||||||
SortablejsModule.forRoot({ animation: 150 }),
|
SortablejsModule.forRoot({ animation: 150 }),
|
||||||
|
TranslateModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AppRootComponent,
|
AppRootComponent,
|
||||||
@@ -127,6 +148,7 @@ const PROVIDERS = [
|
|||||||
AlwaysVisibleTypeaheadDirective,
|
AlwaysVisibleTypeaheadDirective,
|
||||||
SortablejsModule,
|
SortablejsModule,
|
||||||
DragDropModule,
|
DragDropModule,
|
||||||
|
TranslateModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
|
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
|
||||||
@@ -198,9 +220,19 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
static forRoot (): ModuleWithProviders<AppModule> {
|
static forRoot (): ModuleWithProviders<AppModule> {
|
||||||
|
const translateModule = TranslateModule.forRoot({
|
||||||
|
defaultLanguage: 'en',
|
||||||
|
compiler: {
|
||||||
|
provide: TranslateCompiler,
|
||||||
|
useFactory: TranslateMessageFormatCompilerFactory,
|
||||||
|
},
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
ngModule: AppModule,
|
ngModule: AppModule,
|
||||||
providers: PROVIDERS,
|
providers: [
|
||||||
|
...PROVIDERS,
|
||||||
|
...translateModule.providers!.filter(x => x !== TranslateService),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
122
tabby-core/src/services/locale.service.ts
Normal file
122
tabby-core/src/services/locale.service.ts
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
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<string> {
|
||||||
|
return this.localeChanged.pipe(distinctUntilChanged())
|
||||||
|
}
|
||||||
|
|
||||||
|
get catalogChanged$ (): Observable<Record<string, string | undefined>> {
|
||||||
|
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<string>()
|
||||||
|
private catalogChanged = new Subject<Record<string, string | undefined>>()
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private config: ConfigService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
log: LogService,
|
||||||
|
) {
|
||||||
|
this.logger = log.create('translate')
|
||||||
|
config.changed$.subscribe(() => {
|
||||||
|
this.refresh()
|
||||||
|
})
|
||||||
|
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 {
|
||||||
|
this.setLocale(this.config.store.language)
|
||||||
|
}
|
||||||
|
|
||||||
|
async setLocale (lang: string): Promise<void> {
|
||||||
|
const strings = this.translations[lang]
|
||||||
|
|
||||||
|
if (!this.translate.langs.includes(lang)) {
|
||||||
|
this.translate.addLangs([lang])
|
||||||
|
|
||||||
|
// Filter out legacy interpolated strings
|
||||||
|
const filteredStrings = Object.fromEntries(
|
||||||
|
Object.entries(strings).filter(e => !e[0].includes('{{')),
|
||||||
|
)
|
||||||
|
this.translate.setTranslation(lang, filteredStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@@ -14,6 +14,7 @@ import { HotkeysService } from './services/hotkeys.service'
|
|||||||
import { PromptModalComponent } from './components/promptModal.component'
|
import { PromptModalComponent } from './components/promptModal.component'
|
||||||
import { SplitLayoutProfilesService } from './profiles'
|
import { SplitLayoutProfilesService } from './profiles'
|
||||||
import { TAB_COLORS } from './utils'
|
import { TAB_COLORS } from './utils'
|
||||||
|
import { TranslateService } from '@ngx-translate/core'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -22,6 +23,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
|||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
|
private translate: TranslateService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -29,7 +31,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
|||||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
|
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
|
||||||
let items: MenuItemOptions[] = [
|
let items: MenuItemOptions[] = [
|
||||||
{
|
{
|
||||||
label: 'Close',
|
label: this.translate.instant('Close'),
|
||||||
click: () => {
|
click: () => {
|
||||||
if (this.app.tabs.includes(tab)) {
|
if (this.app.tabs.includes(tab)) {
|
||||||
this.app.closeTab(tab, true)
|
this.app.closeTab(tab, true)
|
||||||
@@ -43,7 +45,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
|||||||
items = [
|
items = [
|
||||||
...items,
|
...items,
|
||||||
{
|
{
|
||||||
label: 'Close other tabs',
|
label: this.translate.instant('Close other tabs'),
|
||||||
click: () => {
|
click: () => {
|
||||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||||
this.app.closeTab(t, true)
|
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: () => {
|
click: () => {
|
||||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||||
this.app.closeTab(t, true)
|
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: () => {
|
click: () => {
|
||||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||||
this.app.closeTab(t, true)
|
this.app.closeTab(t, true)
|
||||||
@@ -71,13 +73,13 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
|||||||
if (tab.parent instanceof SplitTabComponent) {
|
if (tab.parent instanceof SplitTabComponent) {
|
||||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Split',
|
label: this.translate.instant('Split'),
|
||||||
submenu: directions.map(dir => ({
|
submenu: directions.map(dir => ({
|
||||||
label: {
|
label: {
|
||||||
r: 'Right',
|
r: this.translate.instant('Right'),
|
||||||
b: 'Down',
|
b: this.translate.instant('Down'),
|
||||||
l: 'Left',
|
l: this.translate.instant('Left'),
|
||||||
t: 'Up',
|
t: this.translate.instant('Up'),
|
||||||
}[dir],
|
}[dir],
|
||||||
click: () => {
|
click: () => {
|
||||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||||
@@ -99,6 +101,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
private app: AppService,
|
private app: AppService,
|
||||||
private ngbModal: NgbModal,
|
private ngbModal: NgbModal,
|
||||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||||
|
private translate: TranslateService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -109,18 +112,18 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
items = [
|
items = [
|
||||||
...items,
|
...items,
|
||||||
{
|
{
|
||||||
label: 'Rename',
|
label: this.translate.instant('Rename'),
|
||||||
click: () => tabHeader.showRenameTabModal(),
|
click: () => tabHeader.showRenameTabModal(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Duplicate',
|
label: this.translate.instant('Duplicate'),
|
||||||
click: () => this.app.duplicateTab(tab),
|
click: () => this.app.duplicateTab(tab),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Color',
|
label: this.translate.instant('Color'),
|
||||||
sublabel: TAB_COLORS.find(x => x.value === tab.color)?.name,
|
sublabel: TAB_COLORS.find(x => x.value === tab.color)?.name,
|
||||||
submenu: TAB_COLORS.map(color => ({
|
submenu: TAB_COLORS.map(color => ({
|
||||||
label: color.name,
|
label: this.translate.instant(color.name),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
checked: tab.color === color.value,
|
checked: tab.color === color.value,
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -132,10 +135,10 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
|
|
||||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Save layout as profile',
|
label: this.translate.instant('Save layout as profile'),
|
||||||
click: async () => {
|
click: async () => {
|
||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
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
|
const name = (await modal.result)?.value
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return
|
return
|
||||||
@@ -154,6 +157,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||||
constructor (
|
constructor (
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
|
private translate: TranslateService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -167,10 +171,10 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
|||||||
if (process) {
|
if (process) {
|
||||||
items.push({
|
items.push({
|
||||||
enabled: false,
|
enabled: false,
|
||||||
label: 'Current process: ' + process.name,
|
label: this.translate.instant('Current process: ' + process.name),
|
||||||
})
|
})
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Notify when done',
|
label: this.translate.instant('Notify when done'),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: extTab.__completionNotificationEnabled,
|
checked: extTab.__completionNotificationEnabled,
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -178,7 +182,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
|||||||
|
|
||||||
if (extTab.__completionNotificationEnabled) {
|
if (extTab.__completionNotificationEnabled) {
|
||||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||||
new Notification('Process completed', {
|
new Notification(this.translate.instant('Process completed'), {
|
||||||
body: process.name,
|
body: process.name,
|
||||||
}).addEventListener('click', () => {
|
}).addEventListener('click', () => {
|
||||||
this.app.selectTab(tab)
|
this.app.selectTab(tab)
|
||||||
@@ -192,7 +196,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Notify on activity',
|
label: this.translate.instant('Notify on activity'),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: !!extTab.__outputNotificationSubscription,
|
checked: !!extTab.__outputNotificationSubscription,
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -204,7 +208,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
|||||||
if (extTab.__outputNotificationSubscription && active) {
|
if (extTab.__outputNotificationSubscription && active) {
|
||||||
extTab.__outputNotificationSubscription.unsubscribe()
|
extTab.__outputNotificationSubscription.unsubscribe()
|
||||||
extTab.__outputNotificationSubscription = null
|
extTab.__outputNotificationSubscription = null
|
||||||
new Notification('Tab activity', {
|
new Notification(this.translate.instant('Tab activity'), {
|
||||||
body: tab.title,
|
body: tab.title,
|
||||||
}).addEventListener('click', () => {
|
}).addEventListener('click', () => {
|
||||||
this.app.selectTab(tab)
|
this.app.selectTab(tab)
|
||||||
|
@@ -2,6 +2,13 @@
|
|||||||
# yarn lockfile v1
|
# 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:
|
agent-base@6:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||||
@@ -56,6 +63,37 @@ js-yaml@^4.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
argparse "^2.0.1"
|
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:
|
mixpanel@^0.13.0:
|
||||||
version "0.13.0"
|
version "0.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.13.0.tgz#699bf510d9ba013c75edcf979ff1e24085fde9d2"
|
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"
|
resize-observer-polyfill "^1.5.0"
|
||||||
tslib "^2.0.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:
|
perfect-scrollbar@1.5.0:
|
||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz#821d224ed8ff61990c23f26db63048cdc75b6b83"
|
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz#821d224ed8ff61990c23f26db63048cdc75b6b83"
|
||||||
@@ -116,11 +161,21 @@ string_decoder@^1.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.2.0"
|
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:
|
tslib@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
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:
|
util-deprecate@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
|
@@ -66,6 +66,15 @@
|
|||||||
|
|
||||||
|
|
||||||
h3 Application settings
|
h3 Application settings
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Language
|
||||||
|
select.form-control([(ngModel)]='config.store.language', (ngModelChange)='saveConfiguration()')
|
||||||
|
option(
|
||||||
|
[value]='lang.code',
|
||||||
|
*ngFor='let lang of locale.allLanguages'
|
||||||
|
) {{lang.name|translate}}
|
||||||
|
|
||||||
.form-line(*ngIf='platform.isShellIntegrationSupported()')
|
.form-line(*ngIf='platform.isShellIntegrationSupported()')
|
||||||
.header
|
.header
|
||||||
.title Shell integration
|
.title Shell integration
|
||||||
|
@@ -12,6 +12,7 @@ import {
|
|||||||
PlatformService,
|
PlatformService,
|
||||||
HostWindowService,
|
HostWindowService,
|
||||||
AppService,
|
AppService,
|
||||||
|
LocaleService,
|
||||||
} from 'tabby-core'
|
} from 'tabby-core'
|
||||||
|
|
||||||
import { SettingsTabProvider } from '../api'
|
import { SettingsTabProvider } from '../api'
|
||||||
@@ -43,6 +44,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
|||||||
public homeBase: HomeBaseService,
|
public homeBase: HomeBaseService,
|
||||||
public platform: PlatformService,
|
public platform: PlatformService,
|
||||||
public zone: NgZone,
|
public zone: NgZone,
|
||||||
|
public locale: LocaleService,
|
||||||
private updater: UpdaterService,
|
private updater: UpdaterService,
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[],
|
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[],
|
||||||
|
@@ -47,6 +47,7 @@ module.exports = options => {
|
|||||||
alias: options.alias ?? {},
|
alias: options.alias ?? {},
|
||||||
modules: ['.', 'src', 'node_modules', '../app/node_modules', '../node_modules'].map(x => path.join(options.dirname, x)),
|
modules: ['.', 'src', 'node_modules', '../app/node_modules', '../node_modules'].map(x => path.join(options.dirname, x)),
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
|
mainFields: ['esm2015', 'browser', 'module', 'main'],
|
||||||
},
|
},
|
||||||
ignoreWarnings: [/Failed to parse source map/],
|
ignoreWarnings: [/Failed to parse source map/],
|
||||||
module: {
|
module: {
|
||||||
|
Reference in New Issue
Block a user