From c556795811f476a3be957da8a35d10ba0784814b Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Tue, 30 Oct 2018 18:17:32 +0000 Subject: [PATCH] mgr/dashboard: Use I18N in TypeScript strings Signed-off-by: Tiago Melo --- .../ceph/block/iscsi/iscsi.component.spec.ts | 5 +- .../app/ceph/block/iscsi/iscsi.component.ts | 31 +-- .../mirroring/mirroring.component.spec.ts | 5 +- .../block/mirroring/mirroring.component.ts | 51 ++--- .../block/rbd-form/rbd-form.component.spec.ts | 5 +- .../ceph/block/rbd-form/rbd-form.component.ts | 16 +- .../rbd-images/rbd-images.component.spec.ts | 4 +- .../block/rbd-list/rbd-list.component.spec.ts | 8 +- .../ceph/block/rbd-list/rbd-list.component.ts | 32 +-- .../rbd-snapshot-form.component.spec.ts | 4 +- .../rbd-snapshot-list.component.spec.ts | 12 +- .../rbd-snapshot-list.component.ts | 20 +- .../rbd-trash-list.component.spec.ts | 4 +- .../rbd-trash-list.component.ts | 18 +- .../rbd-trash-move-modal.component.spec.ts | 4 +- .../rbd-trash-purge-modal.component.spec.ts | 4 +- .../rbd-trash-restore-modal.component.spec.ts | 4 +- .../cephfs-clients.component.spec.ts | 5 +- .../cephfs-clients.component.ts | 16 +- .../cephfs-detail.component.spec.ts | 5 +- .../cephfs-detail/cephfs-detail.component.ts | 26 +-- .../cephfs-list/cephfs-list.component.spec.ts | 5 +- .../cephfs-list/cephfs-list.component.ts | 10 +- .../configuration-details.component.spec.ts | 5 +- .../configuration-details.component.ts | 19 +- .../configuration-form.component.spec.ts | 5 +- .../configuration-form.component.ts | 53 +++-- .../configuration.component.spec.ts | 5 +- .../configuration/configuration.component.ts | 21 +- .../cluster/hosts/hosts.component.spec.ts | 4 +- .../app/ceph/cluster/hosts/hosts.component.ts | 11 +- .../cluster/monitor/monitor.component.spec.ts | 4 +- .../ceph/cluster/monitor/monitor.component.ts | 18 +- .../osd-flags-modal.component.spec.ts | 4 +- .../osd-flags-modal.component.ts | 61 +++--- .../osd/osd-list/osd-list.component.spec.ts | 9 +- .../osd/osd-list/osd-list.component.ts | 79 +++++--- .../osd-scrub-modal.component.spec.ts | 5 +- .../osd-scrub-modal.component.ts | 9 +- .../dashboard/health/health.component.spec.ts | 5 +- .../ceph/dashboard/health/health.component.ts | 21 +- .../ceph/dashboard/mds-summary.pipe.spec.ts | 13 +- .../app/ceph/dashboard/mds-summary.pipe.ts | 12 +- .../ceph/dashboard/mgr-summary.pipe.spec.ts | 14 +- .../app/ceph/dashboard/mgr-summary.pipe.ts | 6 +- .../ceph/dashboard/mon-summary.pipe.spec.ts | 13 +- .../app/ceph/dashboard/mon-summary.pipe.ts | 10 +- .../ceph/dashboard/osd-summary.pipe.spec.ts | 12 +- .../app/ceph/dashboard/osd-summary.pipe.ts | 12 +- .../performance-counter.component.spec.ts | 5 +- ...able-performance-counter.component.spec.ts | 5 +- .../table-performance-counter.component.ts | 10 +- .../erasure-code-profile-form-tooltips.ts | 1 + ...rasure-code-profile-form.component.spec.ts | 4 +- .../app/ceph/pool/pool-form/pool-form-data.ts | 54 +++--- .../pool-form/pool-form.component.spec.ts | 5 +- .../pool/pool-form/pool-form.component.ts | 8 +- .../pool-list/pool-list.component.spec.ts | 5 +- .../pool/pool-list/pool-list.component.ts | 31 +-- .../rgw/rgw-501/rgw-501.component.spec.ts | 5 +- .../rgw-bucket-list.component.spec.ts | 9 +- .../rgw-bucket-list.component.ts | 18 +- .../rgw-daemon-list.component.spec.ts | 5 +- .../rgw-daemon-list.component.ts | 11 +- .../rgw-user-details.component.spec.ts | 4 +- .../rgw-user-details.component.ts | 11 +- .../rgw-user-list.component.spec.ts | 9 +- .../rgw-user-list/rgw-user-list.component.ts | 22 ++- .../role-details.component.spec.ts | 5 +- .../role-details/role-details.component.ts | 13 +- .../role-form/role-form.component.spec.ts | 5 +- .../auth/role-form/role-form.component.ts | 18 +- .../role-list/role-list.component.spec.ts | 9 +- .../auth/role-list/role-list.component.ts | 21 +- .../user-form/user-form.component.spec.ts | 5 +- .../auth/user-form/user-form.component.ts | 14 +- .../user-list/user-list.component.spec.ts | 9 +- .../auth/user-list/user-list.component.ts | 27 +-- .../navigation/navigation.component.spec.ts | 5 +- .../notifications.component.spec.ts | 5 +- .../task-manager.component.spec.ts | 5 +- .../grafana/grafana.component.spec.ts | 4 +- .../info-panel/info-panel.component.spec.ts | 5 +- .../info-panel/info-panel.component.ts | 6 +- .../services/api-interceptor.service.spec.ts | 4 +- .../services/notification.service.spec.ts | 5 +- .../shared/services/task-list.service.spec.ts | 4 +- .../services/task-message.service.spec.ts | 13 +- .../shared/services/task-message.service.ts | 183 +++++++++++++----- .../services/task-wrapper.service.spec.ts | 4 +- .../frontend/src/testing/unit-test-helper.ts | 20 ++ 91 files changed, 850 insertions(+), 485 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.spec.ts index 983051e5562..45648292795 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { TcmuIscsiService } from '../../../shared/api/tcmu-iscsi.service'; import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe'; import { DimlessPipe } from '../../../shared/pipes/dimless.pipe'; @@ -36,7 +36,8 @@ describe('IscsiComponent', () => { FormatterService, RelativeDatePipe, ListPipe, - { provide: TcmuIscsiService, useValue: fakeService } + { provide: TcmuIscsiService, useValue: fakeService }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.ts index b12c7974e57..0b9195ec417 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi/iscsi.component.ts @@ -1,5 +1,7 @@ import { Component } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { TcmuIscsiService } from '../../../shared/api/tcmu-iscsi.service'; import { CellTemplate } from '../../../shared/enum/cell-template.enum'; import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe'; @@ -23,70 +25,71 @@ export class IscsiComponent { cephShortVersionPipe: CephShortVersionPipe, dimlessPipe: DimlessPipe, relativeDatePipe: RelativeDatePipe, - listPipe: ListPipe + listPipe: ListPipe, + private i18n: I18n ) { this.daemonsColumns = [ { - name: 'Hostname', + name: this.i18n('Hostname'), prop: 'server_hostname' }, { - name: '# Active/Optimized', + name: this.i18n('# Active/Optimized'), prop: 'optimized_paths' }, { - name: '# Active/Non-Optimized', + name: this.i18n('# Active/Non-Optimized'), prop: 'non_optimized_paths' }, { - name: 'Version', + name: this.i18n('Version'), prop: 'version', pipe: cephShortVersionPipe } ]; this.imagesColumns = [ { - name: 'Pool', + name: this.i18n('Pool'), prop: 'pool_name' }, { - name: 'Image', + name: this.i18n('Image'), prop: 'name' }, { - name: 'Active/Optimized', + name: this.i18n('Active/Optimized'), prop: 'optimized_paths', pipe: listPipe }, { - name: 'Active/Non-Optimized', + name: this.i18n('Active/Non-Optimized'), prop: 'non_optimized_paths', pipe: listPipe }, { - name: 'Read Bytes', + name: this.i18n('Read Bytes'), prop: 'stats_history.rd_bytes', cellTransformation: CellTemplate.sparkline }, { - name: 'Write Bytes', + name: this.i18n('Write Bytes'), prop: 'stats_history.wr_bytes', cellTransformation: CellTemplate.sparkline }, { - name: 'Read Ops', + name: this.i18n('Read Ops'), prop: 'stats.rd', pipe: dimlessPipe, cellTransformation: CellTemplate.perSecond }, { - name: 'Write Ops', + name: this.i18n('Write Ops'), prop: 'stats.wr', pipe: dimlessPipe, cellTransformation: CellTemplate.perSecond }, { - name: 'A/O Since', + name: this.i18n('A/O Since'), prop: 'optimized_since', pipe: relativeDatePipe } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts index 43647a46ad6..cec99ebf5ea 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts @@ -5,7 +5,7 @@ import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { MirrorHealthColorPipe } from '../mirror-health-color.pipe'; import { MirroringComponent } from './mirroring.component'; @@ -22,7 +22,8 @@ describe('MirroringComponent', () => { TabsModule.forRoot(), ProgressbarModule.forRoot(), HttpClientTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.ts index 11586e8a12b..c39ba3a36eb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/mirroring/mirroring.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { RbdMirroringService } from '../../../shared/api/rbd-mirroring.service'; import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum'; import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe'; @@ -45,78 +47,79 @@ export class MirroringComponent implements OnInit { constructor( private rbdMirroringService: RbdMirroringService, - private cephShortVersionPipe: CephShortVersionPipe + private cephShortVersionPipe: CephShortVersionPipe, + private i18n: I18n ) {} ngOnInit() { this.daemons.columns = [ - { prop: 'instance_id', name: 'Instance', flexGrow: 2 }, - { prop: 'id', name: 'ID', flexGrow: 2 }, - { prop: 'server_hostname', name: 'Hostname', flexGrow: 2 }, + { prop: 'instance_id', name: this.i18n('Instance'), flexGrow: 2 }, + { prop: 'id', name: this.i18n('ID'), flexGrow: 2 }, + { prop: 'server_hostname', name: this.i18n('Hostname'), flexGrow: 2 }, { prop: 'version', - name: 'Version', + name: this.i18n('Version'), pipe: this.cephShortVersionPipe, flexGrow: 2 }, { prop: 'health', - name: 'Health', + name: this.i18n('Health'), cellTemplate: this.healthTmpl, flexGrow: 1 } ]; this.pools.columns = [ - { prop: 'name', name: 'Name', flexGrow: 2 }, - { prop: 'mirror_mode', name: 'Mode', flexGrow: 2 }, - { prop: 'leader_id', name: 'Leader', flexGrow: 2 }, - { prop: 'image_local_count', name: '# Local', flexGrow: 2 }, - { prop: 'image_remote_count', name: '# Remote', flexGrow: 2 }, + { prop: 'name', name: this.i18n('Name'), flexGrow: 2 }, + { prop: 'mirror_mode', name: this.i18n('Mode'), flexGrow: 2 }, + { prop: 'leader_id', name: this.i18n('Leader'), flexGrow: 2 }, + { prop: 'image_local_count', name: this.i18n('# Local'), flexGrow: 2 }, + { prop: 'image_remote_count', name: this.i18n('# Remote'), flexGrow: 2 }, { prop: 'health', - name: 'Health', + name: this.i18n('Health'), cellTemplate: this.healthTmpl, flexGrow: 1 } ]; this.image_error.columns = [ - { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, - { prop: 'name', name: 'Image', flexGrow: 2 }, - { prop: 'description', name: 'Issue', flexGrow: 4 }, + { prop: 'pool_name', name: this.i18n('Pool'), flexGrow: 2 }, + { prop: 'name', name: this.i18n('Image'), flexGrow: 2 }, + { prop: 'description', name: this.i18n('Issue'), flexGrow: 4 }, { prop: 'state', - name: 'State', + name: this.i18n('State'), cellTemplate: this.stateTmpl, flexGrow: 1 } ]; this.image_syncing.columns = [ - { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, - { prop: 'name', name: 'Image', flexGrow: 2 }, + { prop: 'pool_name', name: this.i18n('Pool'), flexGrow: 2 }, + { prop: 'name', name: this.i18n('Image'), flexGrow: 2 }, { prop: 'progress', - name: 'Progress', + name: this.i18n('Progress'), cellTemplate: this.progressTmpl, flexGrow: 2 }, { prop: 'state', - name: 'State', + name: this.i18n('State'), cellTemplate: this.syncTmpl, flexGrow: 1 } ]; this.image_ready.columns = [ - { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, - { prop: 'name', name: 'Image', flexGrow: 2 }, - { prop: 'description', name: 'Description', flexGrow: 4 }, + { prop: 'pool_name', name: this.i18n('Pool'), flexGrow: 2 }, + { prop: 'name', name: this.i18n('Image'), flexGrow: 2 }, + { prop: 'description', name: this.i18n('Description'), flexGrow: 4 }, { prop: 'state', - name: 'State', + name: this.i18n('State'), cellTemplate: this.stateTmpl, flexGrow: 1 } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts index 0dfdafadc1c..06dc9fb5e14 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts @@ -7,7 +7,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { ActivatedRouteStub } from '../../../../testing/activated-route-stub'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { RbdService } from '../../../shared/api/rbd.service'; import { SharedModule } from '../../../shared/shared.module'; import { RbdFormMode } from './rbd-form-mode.enum'; @@ -31,7 +31,8 @@ describe('RbdFormComponent', () => { { provide: ActivatedRoute, useValue: new ActivatedRouteStub({ pool: 'foo', name: 'bar', snap: undefined }) - } + }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts index 08f1a8d6c71..911456de88b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormControl, ValidatorFn, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { Observable } from 'rxjs'; @@ -81,42 +82,43 @@ export class RbdFormComponent implements OnInit { private rbdService: RbdService, private formatter: FormatterService, private taskWrapper: TaskWrapperService, - private dimlessBinaryPipe: DimlessBinaryPipe + private dimlessBinaryPipe: DimlessBinaryPipe, + private i18n: I18n ) { this.poolPermission = this.authStorageService.getPermissions().pool; this.features = { 'deep-flatten': { - desc: 'Deep flatten', + desc: this.i18n('Deep flatten'), requires: null, allowEnable: false, allowDisable: true }, layering: { - desc: 'Layering', + desc: this.i18n('Layering'), requires: null, allowEnable: false, allowDisable: false }, 'exclusive-lock': { - desc: 'Exclusive lock', + desc: this.i18n('Exclusive lock'), requires: null, allowEnable: true, allowDisable: true }, 'object-map': { - desc: 'Object map (requires exclusive-lock)', + desc: this.i18n('Object map (requires exclusive-lock)'), requires: 'exclusive-lock', allowEnable: true, allowDisable: true }, journaling: { - desc: 'Journaling (requires exclusive-lock)', + desc: this.i18n('Journaling (requires exclusive-lock)'), requires: 'exclusive-lock', allowEnable: true, allowDisable: true }, 'fast-diff': { - desc: 'Fast diff (requires object-map)', + desc: this.i18n('Fast diff (requires object-map)'), requires: 'object-map', allowEnable: true, allowDisable: true diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-images/rbd-images.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-images/rbd-images.component.spec.ts index 99697264f72..7ea48745072 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-images/rbd-images.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-images/rbd-images.component.spec.ts @@ -6,7 +6,7 @@ import { ToastModule } from 'ng2-toastr'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { TaskListService } from '../../../shared/services/task-list.service'; import { SharedModule } from '../../../shared/shared.module'; import { RbdDetailsComponent } from '../rbd-details/rbd-details.component'; @@ -35,7 +35,7 @@ describe('RbdImagesComponent', () => { ToastModule.forRoot(), TooltipModule.forRoot() ], - providers: [TaskListService] + providers: [TaskListService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts index cddb711503c..e9631eabdf7 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts @@ -11,7 +11,11 @@ import { TabsModule } from 'ngx-bootstrap/tabs'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; import { BehaviorSubject, of } from 'rxjs'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { RbdService } from '../../../shared/api/rbd.service'; import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component'; import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum'; @@ -47,7 +51,7 @@ describe('RbdListComponent', () => { HttpClientTestingModule ], declarations: [RbdListComponent, RbdDetailsComponent, RbdSnapshotListComponent], - providers: [TaskListService] + providers: [TaskListService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts index 6593096d649..97051ca5cea 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; @@ -75,7 +76,8 @@ export class RbdListComponent implements OnInit { private dimlessPipe: DimlessPipe, private modalService: BsModalService, private taskWrapper: TaskWrapperService, - private taskListService: TaskListService + private taskListService: TaskListService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().rbdImage; const getImageUri = () => @@ -86,19 +88,19 @@ export class RbdListComponent implements OnInit { icon: 'fa-plus', routerLink: () => '/block/rbd/add', canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection, - name: 'Add' + name: this.i18n('Add') }; const editAction: CdTableAction = { permission: 'update', icon: 'fa-pencil', routerLink: () => `/block/rbd/edit/${getImageUri()}`, - name: 'Edit' + name: this.i18n('Edit') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', click: () => this.deleteRbdModal(), - name: 'Delete' + name: this.i18n('Delete') }; const copyAction: CdTableAction = { permission: 'create', @@ -107,7 +109,7 @@ export class RbdListComponent implements OnInit { !selection.hasSingleSelection || selection.first().cdExecuting, icon: 'fa-copy', routerLink: () => `/block/rbd/copy/${getImageUri()}`, - name: 'Copy' + name: this.i18n('Copy') }; const flattenAction: CdTableAction = { permission: 'update', @@ -115,13 +117,13 @@ export class RbdListComponent implements OnInit { !selection.hasSingleSelection || selection.first().cdExecuting || !selection.first().parent, icon: 'fa-chain-broken', click: () => this.flattenRbdModal(), - name: 'Flatten' + name: this.i18n('Flatten') }; const moveAction: CdTableAction = { permission: 'delete', icon: 'fa-trash-o', click: () => this.trashRbdModal(), - name: 'Move to Trash' + name: this.i18n('Move to Trash') }; this.tableActions = [ addAction, @@ -136,53 +138,53 @@ export class RbdListComponent implements OnInit { ngOnInit() { this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'name', flexGrow: 2, cellTransformation: CellTemplate.executing }, { - name: 'Pool', + name: this.i18n('Pool'), prop: 'pool_name', flexGrow: 2 }, { - name: 'Size', + name: this.i18n('Size'), prop: 'size', flexGrow: 1, cellClass: 'text-right', pipe: this.dimlessBinaryPipe }, { - name: 'Objects', + name: this.i18n('Objects'), prop: 'num_objs', flexGrow: 1, cellClass: 'text-right', pipe: this.dimlessPipe }, { - name: 'Object size', + name: this.i18n('Object size'), prop: 'obj_size', flexGrow: 1, cellClass: 'text-right', pipe: this.dimlessBinaryPipe }, { - name: 'Provisioned', + name: this.i18n('Provisioned'), prop: 'disk_usage', cellClass: 'text-center', flexGrow: 1, pipe: this.dimlessBinaryPipe }, { - name: 'Total provisioned', + name: this.i18n('Total provisioned'), prop: 'total_disk_usage', cellClass: 'text-center', flexGrow: 1, pipe: this.dimlessBinaryPipe }, { - name: 'Parent', + name: this.i18n('Parent'), prop: 'parent', flexGrow: 2, cellTemplate: this.parentTpl diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.spec.ts index 2e881b49275..9dea478ef8a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.spec.ts @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { ApiModule } from '../../../shared/api/api.module'; import { ComponentsModule } from '../../../shared/components/components.module'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; @@ -28,7 +28,7 @@ describe('RbdSnapshotFormComponent', () => { RouterTestingModule ], declarations: [RbdSnapshotFormComponent], - providers: [BsModalRef, BsModalService, AuthStorageService] + providers: [BsModalRef, BsModalService, AuthStorageService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts index 39a8d10d09f..41861135fe2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts @@ -7,7 +7,11 @@ import { ToastModule } from 'ng2-toastr'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { Subject, throwError as observableThrowError } from 'rxjs'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { ApiModule } from '../../../shared/api/api.module'; import { RbdService } from '../../../shared/api/rbd.service'; import { ComponentsModule } from '../../../shared/components/components.module'; @@ -50,7 +54,11 @@ describe('RbdSnapshotListComponent', () => { RouterTestingModule, PipesModule ], - providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }, TaskListService] + providers: [ + { provide: AuthStorageService, useValue: fakeAuthStorageService }, + TaskListService, + i18nProviders + ] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts index f6d3cbd7067..8958dea84b2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as moment from 'moment'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { of } from 'rxjs'; @@ -72,7 +73,8 @@ export class RbdSnapshotListComponent implements OnInit, OnChanges { private taskManagerService: TaskManagerService, private notificationService: NotificationService, private summaryService: SummaryService, - private taskListService: TaskListService + private taskListService: TaskListService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().rbdImage; const actions = new RbdSnapshotActionsModel(); @@ -95,34 +97,34 @@ export class RbdSnapshotListComponent implements OnInit, OnChanges { ngOnInit() { this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'name', cellTransformation: CellTemplate.executing, flexGrow: 2 }, { - name: 'Size', + name: this.i18n('Size'), prop: 'size', flexGrow: 1, cellClass: 'text-right', pipe: this.dimlessBinaryPipe }, { - name: 'Provisioned', + name: this.i18n('Provisioned'), prop: 'disk_usage', flexGrow: 1, cellClass: 'text-right', pipe: this.dimlessBinaryPipe }, { - name: 'State', + name: this.i18n('State'), prop: 'is_protected', flexGrow: 1, cellClass: 'text-center', cellTemplate: this.protectTpl }, { - name: 'Created', + name: this.i18n('Created'), prop: 'timestamp', flexGrow: 1, pipe: this.cdDatePipe @@ -253,8 +255,8 @@ export class RbdSnapshotListComponent implements OnInit, OnChanges { rollbackModal() { const snapshotName = this.selection.selected[0].name; const initialState = { - titleText: 'RBD snapshot rollback', - buttonText: 'Rollback', + titleText: this.i18n('RBD snapshot rollback'), + buttonText: this.i18n('Rollback'), bodyTpl: this.rollbackTpl, bodyData: { snapName: `${this.poolName}/${this.rbdName}@${snapshotName}` @@ -271,7 +273,7 @@ export class RbdSnapshotListComponent implements OnInit, OnChanges { const snapshotName = this.selection.selected[0].name; this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, { initialState: { - itemDescription: 'RBD snapshot', + itemDescription: this.i18n('RBD snapshot'), submitAction: () => this._asyncTask('deleteSnapshot', 'rbd/snap/delete', snapshotName) } }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.spec.ts index c256c8739f9..5f8126aa428 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.spec.ts @@ -6,7 +6,7 @@ import { ToastModule } from 'ng2-toastr'; import { of } from 'rxjs'; import { By } from '@angular/platform-browser'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { RbdService } from '../../../shared/api/rbd.service'; import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { ExecutingTask } from '../../../shared/models/executing-task'; @@ -24,7 +24,7 @@ describe('RbdTrashListComponent', () => { configureTestBed({ declarations: [RbdTrashListComponent], imports: [SharedModule, HttpClientTestingModule, RouterTestingModule, ToastModule.forRoot()], - providers: [TaskListService] + providers: [TaskListService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts index ac6059d5bbc..71f32dbeb28 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import * as moment from 'moment'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; @@ -52,7 +53,8 @@ export class RbdTrashListComponent implements OnInit { private modalService: BsModalService, private cdDatePipe: CdDatePipe, private taskListService: TaskListService, - private taskWrapper: TaskWrapperService + private taskWrapper: TaskWrapperService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().rbdImage; @@ -60,13 +62,13 @@ export class RbdTrashListComponent implements OnInit { permission: 'update', icon: 'fa-undo', click: () => this.restoreModal(), - name: 'Restore' + name: this.i18n('Restore') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', click: () => this.deleteModal(), - name: 'Delete' + name: this.i18n('Delete') }; this.tableActions = [restoreAction, deleteAction]; } @@ -74,29 +76,29 @@ export class RbdTrashListComponent implements OnInit { ngOnInit() { this.columns = [ { - name: 'ID', + name: this.i18n('ID'), prop: 'id', flexGrow: 1, cellTransformation: CellTemplate.executing }, { - name: 'Name', + name: this.i18n('Name'), prop: 'name', flexGrow: 1 }, { - name: 'Pool', + name: this.i18n('Pool'), prop: 'pool_name', flexGrow: 1 }, { - name: 'Status', + name: this.i18n('Status'), prop: 'deferment_end_time', flexGrow: 1, cellTemplate: this.expiresTpl }, { - name: 'Deleted At', + name: this.i18n('Deleted At'), prop: 'deletion_time', flexGrow: 1, pipe: this.cdDatePipe diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-move-modal/rbd-trash-move-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-move-modal/rbd-trash-move-modal.component.spec.ts index beea09718e8..737d6b5b662 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-move-modal/rbd-trash-move-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-move-modal/rbd-trash-move-modal.component.spec.ts @@ -8,7 +8,7 @@ import { ToastModule } from 'ng2-toastr'; import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { NotificationService } from '../../../shared/services/notification.service'; import { SharedModule } from '../../../shared/shared.module'; import { RbdTrashMoveModalComponent } from './rbd-trash-move-modal.component'; @@ -28,7 +28,7 @@ describe('RbdTrashMoveModalComponent', () => { BsDatepickerModule.forRoot() ], declarations: [RbdTrashMoveModalComponent], - providers: [BsModalRef, BsModalService] + providers: [BsModalRef, BsModalService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.spec.ts index c4ce343d4ef..749236c0da0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.spec.ts @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { BsModalRef } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { Permission } from '../../../shared/models/permissions'; import { NotificationService } from '../../../shared/services/notification.service'; import { SharedModule } from '../../../shared/shared.module'; @@ -26,7 +26,7 @@ describe('RbdTrashPurgeModalComponent', () => { RouterTestingModule ], declarations: [RbdTrashPurgeModalComponent], - providers: [BsModalRef] + providers: [BsModalRef, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-restore-modal/rbd-trash-restore-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-restore-modal/rbd-trash-restore-modal.component.spec.ts index 06e4d1a33ea..3689b2a18cb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-restore-modal/rbd-trash-restore-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-restore-modal/rbd-trash-restore-modal.component.spec.ts @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { BsModalRef } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { NotificationService } from '../../../shared/services/notification.service'; import { SharedModule } from '../../../shared/shared.module'; import { RbdTrashRestoreModalComponent } from './rbd-trash-restore-modal.component'; @@ -24,7 +24,7 @@ describe('RbdTrashRestoreModalComponent', () => { SharedModule, RouterTestingModule ], - providers: [BsModalRef] + providers: [BsModalRef, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.spec.ts index 9cc2b82a2c2..4b5ab9a16bc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.spec.ts @@ -4,7 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { CephfsClientsComponent } from './cephfs-clients.component'; @@ -19,7 +19,8 @@ describe('CephfsClientsComponent', () => { SharedModule, HttpClientTestingModule ], - declarations: [CephfsClientsComponent] + declarations: [CephfsClientsComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.ts index 093563155fb..af8181ac385 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-clients/cephfs-clients.component.ts @@ -1,5 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { CephfsService } from '../../../shared/api/cephfs.service'; import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum'; @@ -15,17 +17,17 @@ export class CephfsClientsComponent implements OnInit { clients: any; viewCacheStatus: ViewCacheStatus; - constructor(private cephfsService: CephfsService) {} + constructor(private cephfsService: CephfsService, private i18n: I18n) {} ngOnInit() { this.clients = { columns: [ - { prop: 'id' }, - { prop: 'type' }, - { prop: 'state' }, - { prop: 'version' }, - { prop: 'hostname', name: 'Host' }, - { prop: 'root' } + { prop: 'id', name: this.i18n('id') }, + { prop: 'type', name: this.i18n('type') }, + { prop: 'state', name: this.i18n('state') }, + { prop: 'version', name: this.i18n('version') }, + { prop: 'hostname', name: this.i18n('Host') }, + { prop: 'root', name: this.i18n('root') } ], data: [] }; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.spec.ts index 07862a062b8..256db87fa44 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.spec.ts @@ -7,7 +7,7 @@ import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { CephfsDetailComponent } from './cephfs-detail.component'; @@ -36,7 +36,8 @@ describe('CephfsDetailComponent', () => { TabsModule.forRoot(), HttpClientTestingModule ], - declarations: [CephfsDetailComponent, CephfsChartStubComponent, CephfsClientsStubComponent] + declarations: [CephfsDetailComponent, CephfsChartStubComponent, CephfsClientsStubComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.ts index e536e455037..a5ef1733c69 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-detail/cephfs-detail.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { CephfsService } from '../../../shared/api/cephfs.service'; @@ -38,7 +39,8 @@ export class CephfsDetailComponent implements OnChanges, OnInit { constructor( private cephfsService: CephfsService, private dimlessBinary: DimlessBinaryPipe, - private dimless: DimlessPipe + private dimless: DimlessPipe, + private i18n: I18n ) {} ngOnChanges() { @@ -60,23 +62,23 @@ export class CephfsDetailComponent implements OnChanges, OnInit { ngOnInit() { this.ranks = { columns: [ - { prop: 'rank' }, - { prop: 'state' }, - { prop: 'mds', name: 'Daemon' }, - { prop: 'activity', cellTemplate: this.activityTmpl }, - { prop: 'dns', name: 'Dentries', pipe: this.dimless }, - { prop: 'inos', name: 'Inodes', pipe: this.dimless } + { prop: 'rank', name: this.i18n('Rank') }, + { prop: 'state', name: this.i18n('State') }, + { prop: 'mds', name: this.i18n('Daemon') }, + { prop: 'activity', name: this.i18n('Activity'), cellTemplate: this.activityTmpl }, + { prop: 'dns', name: this.i18n('Dentries'), pipe: this.dimless }, + { prop: 'inos', name: this.i18n('Inodes'), pipe: this.dimless } ], data: [] }; this.pools = { columns: [ - { prop: 'pool' }, - { prop: 'type' }, - { prop: 'size', pipe: this.dimlessBinary }, + { prop: 'pool', name: this.i18n('Pool') }, + { prop: 'type', name: this.i18n('Type') }, + { prop: 'size', name: this.i18n('Size'), pipe: this.dimlessBinary }, { - name: 'Usage', + name: this.i18n('Usage'), cellTemplate: this.poolUsageTpl, comparator: (valueA, valueB, rowA, rowB, sortDirection) => { const valA = rowA.used / rowA.avail; @@ -107,7 +109,7 @@ export class CephfsDetailComponent implements OnChanges, OnInit { }); this.standbys = [ { - key: 'Standby daemons', + key: this.i18n('Standby daemons'), value: data.standbys.map((value) => value.name).join(', ') } ]; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.spec.ts index 2f85abc49af..111a6a46836 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.spec.ts @@ -2,7 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Component, Input } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { SharedModule } from '../../../shared/shared.module'; import { CephfsListComponent } from './cephfs-list.component'; @@ -19,7 +19,8 @@ describe('CephfsListComponent', () => { configureTestBed({ imports: [SharedModule, HttpClientTestingModule], - declarations: [CephfsListComponent, CephfsDetailStubComponent] + declarations: [CephfsListComponent, CephfsDetailStubComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts index 346d90f75d1..d58357d4ba8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { CephfsService } from '../../../shared/api/cephfs.service'; import { CdTableColumn } from '../../../shared/models/cd-table-column'; import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context'; @@ -15,22 +17,22 @@ export class CephfsListComponent implements OnInit { filesystems: any = []; selection = new CdTableSelection(); - constructor(private cephfsService: CephfsService) {} + constructor(private cephfsService: CephfsService, private i18n: I18n) {} ngOnInit() { this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'mdsmap.fs_name', flexGrow: 2 }, { - name: 'Created', + name: this.i18n('Created'), prop: 'mdsmap.created', flexGrow: 2 }, { - name: 'Enabled', + name: this.i18n('Enabled'), prop: 'mdsmap.enabled', flexGrow: 1 } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.spec.ts index 763c47f58ed..0016b478696 100755 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper'; import { DataTableModule } from '../../../../shared/datatable/datatable.module'; import { ConfigurationDetailsComponent } from './configuration-details.component'; @@ -12,7 +12,8 @@ describe('ConfigurationDetailsComponent', () => { configureTestBed({ declarations: [ConfigurationDetailsComponent], - imports: [DataTableModule, TabsModule.forRoot()] + imports: [DataTableModule, TabsModule.forRoot()], + providers: [i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.ts index 5ab66d78f86..25876369667 100755 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-details/configuration-details.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { CdTableSelection } from '../../../../shared/models/cd-table-selection'; @@ -14,17 +15,17 @@ export class ConfigurationDetailsComponent implements OnChanges { selection: CdTableSelection; selectedItem: any; flags = { - runtime: 'The value can be updated at runtime.', - no_mon_update: - 'Daemons/clients do not pull this value from the monitor config database. ' + - `We disallow setting this option via 'ceph config set ...'. This option should be ` + - 'configured via ceph.conf or via the command line.', - startup: 'Option takes effect only during daemon startup.', - cluster_create: 'Option only affects cluster creation.', - create: 'Option only affects daemon creation.' + runtime: this.i18n('The value can be updated at runtime.'), + no_mon_update: this.i18n(`Daemons/clients do not pull this value from the + monitor config database. We disallow setting this option via 'ceph config + set ...'. This option should be configured via ceph.conf or via the + command line.`), + startup: this.i18n('Option takes effect only during daemon startup.'), + cluster_create: this.i18n('Option only affects cluster creation.'), + create: this.i18n('Option only affects daemon creation.') }; - constructor() {} + constructor(private i18n: I18n) {} ngOnChanges() { if (this.selection.hasSelection) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.spec.ts index 2d369db25b3..6a67cd77c1c 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.spec.ts @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; -import { configureTestBed } from '../../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper'; import { SharedModule } from '../../../../shared/shared.module'; import { ConfigurationFormComponent } from './configuration-form.component'; import { ConfigFormModel } from './configuration-form.model'; @@ -27,7 +27,8 @@ describe('ConfigurationFormComponent', () => { providers: [ { provide: ActivatedRoute - } + }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts index 65972f395dc..87275ad2e6e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { ConfigurationService } from '../../../../shared/api/configuration.service'; @@ -32,7 +33,8 @@ export class ConfigurationFormComponent implements OnInit { private route: ActivatedRoute, private router: Router, private configService: ConfigurationService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) { this.createForm(); } @@ -69,63 +71,74 @@ export class ConfigurationFormComponent implements OnInit { { name: 'uint64_t', inputType: 'number', - humanReadable: 'Positive integer value', + humanReadable: this.i18n('Positive integer value'), defaultMin: 0, - patternHelpText: 'The entered value needs to be a positive number.', + patternHelpText: this.i18n('The entered value needs to be a positive number.'), isNumberType: true, allowsNegative: false }, { name: 'int64_t', inputType: 'number', - humanReadable: 'Integer value', - patternHelpText: 'The entered value needs to be a number.', + humanReadable: this.i18n('Integer value'), + patternHelpText: this.i18n('The entered value needs to be a number.'), isNumberType: true, allowsNegative: true }, { name: 'size_t', inputType: 'number', - humanReadable: 'Positive integer value (size)', + humanReadable: this.i18n('Positive integer value (size)'), defaultMin: 0, - patternHelpText: 'The entered value needs to be a positive number.', + patternHelpText: this.i18n('The entered value needs to be a positive number.'), isNumberType: true, allowsNegative: false }, { name: 'secs', inputType: 'number', - humanReadable: 'Positive integer value (secs)', + humanReadable: this.i18n('Positive integer value (secs)'), defaultMin: 1, - patternHelpText: 'The entered value needs to be a positive number.', + patternHelpText: this.i18n('The entered value needs to be a positive number.'), isNumberType: true, allowsNegative: false }, { name: 'double', inputType: 'number', - humanReadable: 'Decimal value', - patternHelpText: 'The entered value needs to be a number or decimal.', + humanReadable: this.i18n('Decimal value'), + patternHelpText: this.i18n('The entered value needs to be a number or decimal.'), isNumberType: true, allowsNegative: true }, - { name: 'std::string', inputType: 'text', humanReadable: 'Text', isNumberType: false }, + { + name: 'std::string', + inputType: 'text', + humanReadable: this.i18n('Text'), + isNumberType: false + }, { name: 'entity_addr_t', inputType: 'text', - humanReadable: 'IPv4 or IPv6 address', - patternHelpText: 'The entered value needs to be a valid IP address.', + humanReadable: this.i18n('IPv4 or IPv6 address'), + patternHelpText: this.i18n('The entered value needs to be a valid IP address.'), isNumberType: false }, { name: 'uuid_d', inputType: 'text', - humanReadable: 'UUID', - patternHelpText: - 'The entered value is not a valid UUID, e.g.: 67dcac9f-2c03-4d6c-b7bd-1210b3a259a8', + humanReadable: this.i18n('UUID'), + patternHelpText: this.i18n( + 'The entered value is not a valid UUID, e.g.: 67dcac9f-2c03-4d6c-b7bd-1210b3a259a8' + ), isNumberType: false }, - { name: 'bool', inputType: 'checkbox', humanReadable: 'Boolean value', isNumberType: false } + { + name: 'bool', + inputType: 'checkbox', + humanReadable: this.i18n('Boolean value'), + isNumberType: false + } ]; let currentType = null; @@ -271,8 +284,8 @@ export class ConfigurationFormComponent implements OnInit { () => { this.notificationService.show( NotificationType.success, - 'Config option ' + request.name + ' has been updated.', - 'Update config option' + this.i18n('Config option {{name}} has been updated.', { name: request.name }), + this.i18n('Update config option') ); this.router.navigate(['/configuration']); }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.spec.ts index 956d8ab6d9a..b58ef58c938 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.spec.ts @@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { ConfigurationDetailsComponent } from './configuration-details/configuration-details.component'; import { ConfigurationComponent } from './configuration.component'; @@ -22,7 +22,8 @@ describe('ConfigurationComponent', () => { TabsModule.forRoot(), HttpClientTestingModule, RouterTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.ts index 65e95b4f5bc..3f33a43b4e6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { ConfigurationService } from '../../../shared/api/configuration.service'; import { CdTableAction } from '../../../shared/models/cd-table-action'; import { CdTableColumn } from '../../../shared/models/cd-table-column'; @@ -21,7 +23,7 @@ export class ConfigurationComponent implements OnInit { selection = new CdTableSelection(); filters = [ { - label: 'Level', + label: this.i18n('Level'), prop: 'level', value: 'basic', options: ['basic', 'advanced', 'dev'], @@ -38,7 +40,7 @@ export class ConfigurationComponent implements OnInit { } }, { - label: 'Service', + label: this.i18n('Service'), prop: 'services', value: 'any', options: ['any', 'mon', 'mgr', 'osd', 'mds', 'common', 'mds_client', 'rgw'], @@ -51,7 +53,7 @@ export class ConfigurationComponent implements OnInit { } }, { - label: 'Source', + label: this.i18n('Source'), prop: 'source', value: 'any', options: ['any', 'mon'], @@ -76,7 +78,8 @@ export class ConfigurationComponent implements OnInit { constructor( private authStorageService: AuthStorageService, - private configurationService: ConfigurationService + private configurationService: ConfigurationService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().configOpt; const getConfigOptUri = () => @@ -85,22 +88,22 @@ export class ConfigurationComponent implements OnInit { permission: 'update', icon: 'fa-pencil', routerLink: () => `/configuration/edit/${getConfigOptUri()}`, - name: 'Edit' + name: this.i18n('Edit') }; this.tableActions = [editAction]; } ngOnInit() { this.columns = [ - { canAutoResize: true, prop: 'name' }, - { prop: 'desc', name: 'Description', cellClass: 'wrap' }, + { canAutoResize: true, prop: 'name', name: this.i18n('Name') }, + { prop: 'desc', name: this.i18n('Description'), cellClass: 'wrap' }, { prop: 'value', - name: 'Current value', + name: this.i18n('Current value'), cellClass: 'wrap', cellTemplate: this.confValTpl }, - { prop: 'default', cellClass: 'wrap' } + { prop: 'default', name: this.i18n('Default'), cellClass: 'wrap' } ]; } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts index dad77a63f06..d1264d52e8a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts @@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { HostService } from '../../../shared/api/host.service'; import { Permissions } from '../../../shared/models/permissions'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; @@ -32,7 +32,7 @@ describe('HostsComponent', () => { BsDropdownModule.forRoot(), RouterTestingModule ], - providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }], + providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }, i18nProviders], declarations: [HostsComponent, HostDetailsComponent] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts index d88af19ca00..61c74f47680 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { HostService } from '../../../shared/api/host.service'; import { CdTableColumn } from '../../../shared/models/cd-table-column'; import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context'; @@ -27,7 +29,8 @@ export class HostsComponent implements OnInit { constructor( private authStorageService: AuthStorageService, private hostService: HostService, - private cephShortVersionPipe: CephShortVersionPipe + private cephShortVersionPipe: CephShortVersionPipe, + private i18n: I18n ) { this.permissions = this.authStorageService.getPermissions(); } @@ -35,18 +38,18 @@ export class HostsComponent implements OnInit { ngOnInit() { this.columns = [ { - name: 'Hostname', + name: this.i18n('Hostname'), prop: 'hostname', flexGrow: 1 }, { - name: 'Services', + name: this.i18n('Services'), prop: 'services', flexGrow: 3, cellTemplate: this.servicesTpl }, { - name: 'Version', + name: this.i18n('Version'), prop: 'ceph_version', flexGrow: 1, pipe: this.cephShortVersionPipe diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts index a405a62662f..497ca3b6e08 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts @@ -1,7 +1,7 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { MonitorService } from '../../../shared/api/monitor.service'; import { MonitorComponent } from './monitor.component'; @@ -14,7 +14,7 @@ describe('MonitorComponent', () => { configureTestBed({ declarations: [MonitorComponent], schemas: [NO_ERRORS_SCHEMA], - providers: [{ provide: MonitorService, useValue: fakeService }] + providers: [{ provide: MonitorService, useValue: fakeService }, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts index 0231e0c22ca..6050ded5097 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts @@ -1,5 +1,7 @@ import { Component } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { MonitorService } from '../../../shared/api/monitor.service'; import { CellTemplate } from '../../../shared/enum/cell-template.enum'; @@ -19,15 +21,15 @@ export class MonitorComponent { width: '50%' }; - constructor(private monitorService: MonitorService) { + constructor(private monitorService: MonitorService, private i18n: I18n) { this.inQuorum = { columns: [ - { prop: 'name', name: 'Name', cellTransformation: CellTemplate.routerLink }, - { prop: 'rank', name: 'Rank' }, - { prop: 'public_addr', name: 'Public Address' }, + { prop: 'name', name: this.i18n('Name'), cellTransformation: CellTemplate.routerLink }, + { prop: 'rank', name: this.i18n('Rank') }, + { prop: 'public_addr', name: this.i18n('Public Address') }, { prop: 'cdOpenSessions', - name: 'Open Sessions', + name: this.i18n('Open Sessions'), cellTransformation: CellTemplate.sparkline } ], @@ -36,9 +38,9 @@ export class MonitorComponent { this.notInQuorum = { columns: [ - { prop: 'name', name: 'Name', cellTransformation: CellTemplate.routerLink }, - { prop: 'rank', name: 'Rank' }, - { prop: 'public_addr', name: 'Public Address' } + { prop: 'name', name: this.i18n('Name'), cellTransformation: CellTemplate.routerLink }, + { prop: 'rank', name: this.i18n('Rank') }, + { prop: 'public_addr', name: this.i18n('Public Address') } ], data: [] }; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.spec.ts index 32247d557b9..b74f80f1853 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.spec.ts @@ -6,7 +6,7 @@ import * as _ from 'lodash'; import { ToastModule } from 'ng2-toastr'; import { BsModalRef, ModalModule } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper'; import { NotificationType } from '../../../../shared/enum/notification-type.enum'; import { NotificationService } from '../../../../shared/services/notification.service'; import { SharedModule } from '../../../../shared/shared.module'; @@ -33,7 +33,7 @@ describe('OsdFlagsModalComponent', () => { ToastModule.forRoot() ], declarations: [OsdFlagsModalComponent], - providers: [BsModalRef] + providers: [BsModalRef, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.ts index f195df1ecf6..c78b49137a0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalRef } from 'ngx-bootstrap/modal'; @@ -19,78 +20,83 @@ export class OsdFlagsModalComponent implements OnInit { allFlags = { noin: { code: 'noin', - name: 'No In', + name: this.i18n('No In'), value: false, - description: 'OSDs that were previously marked out will not be marked back in when they start' + description: this.i18n( + 'OSDs that were previously marked out will not be marked back in when they start' + ) }, noout: { code: 'noout', - name: 'No Out', + name: this.i18n('No Out'), value: false, - description: 'OSDs will not automatically be marked out after the configured interval' + description: this.i18n( + 'OSDs will not automatically be marked out after the configured interval' + ) }, noup: { code: 'noup', - name: 'No Up', + name: this.i18n('No Up'), value: false, - description: 'OSDs are not allowed to start' + description: this.i18n('OSDs are not allowed to start') }, nodown: { code: 'nodown', - name: 'No Down', + name: this.i18n('No Down'), value: false, - description: + description: this.i18n( 'OSD failure reports are being ignored, such that the monitors will not mark OSDs down' + ) }, pause: { code: 'pause', - name: 'Pause', + name: this.i18n('Pause'), value: false, - description: 'Pauses reads and writes' + description: this.i18n('Pauses reads and writes') }, noscrub: { code: 'noscrub', - name: 'No Scrub', + name: this.i18n('No Scrub'), value: false, - description: 'Scrubbing is disabled' + description: this.i18n('Scrubbing is disabled') }, 'nodeep-scrub': { code: 'nodeep-scrub', - name: 'No Deep Scrub', + name: this.i18n('No Deep Scrub'), value: false, - description: 'Deep Scrubbing is disabled' + description: this.i18n('Deep Scrubbing is disabled') }, nobackfill: { code: 'nobackfill', - name: 'No Backfill', + name: this.i18n('No Backfill'), value: false, - description: 'Backfilling of PGs is suspended' + description: this.i18n('Backfilling of PGs is suspended') }, norecover: { code: 'norecover', - name: 'No Recover', + name: this.i18n('No Recover'), value: false, - description: 'Recovery of PGs is suspended' + description: this.i18n('Recovery of PGs is suspended') }, sortbitwise: { code: 'sortbitwise', - name: 'Bitwise Sort', + name: this.i18n('Bitwise Sort'), value: false, - description: 'Use bitwise sort', + description: this.i18n('Use bitwise sort'), disabled: true }, purged_snapdirs: { code: 'purged_snapdirs', - name: 'Purged Snapdirs', + name: this.i18n('Purged Snapdirs'), value: false, - description: 'OSDs have converted snapsets', + description: this.i18n('OSDs have converted snapsets'), disabled: true }, recovery_deletes: { code: 'recovery_deletes', - name: 'Recovery Deletes', + name: this.i18n('Recovery Deletes'), value: false, - description: 'Deletes performed during recovery instead of peering', + description: this.i18n('Deletes performed during recovery instead of peering'), disabled: true } }; @@ -100,7 +106,8 @@ export class OsdFlagsModalComponent implements OnInit { constructor( public bsModalRef: BsModalRef, private osdService: OsdService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) {} ngOnInit() { @@ -126,8 +133,8 @@ export class OsdFlagsModalComponent implements OnInit { () => { this.notificationService.show( NotificationType.success, - 'OSD Flags were updated successfully.', - 'OSD Flags' + this.i18n('OSD Flags were updated successfully.'), + this.i18n('OSD Flags') ); this.bsModalRef.hide(); }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts index 02a17796dd6..53fb10e29a3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts @@ -8,7 +8,11 @@ import { BsModalService } from 'ngx-bootstrap/modal'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { EMPTY, of } from 'rxjs'; -import { configureTestBed, PermissionHelper } from '../../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../../testing/unit-test-helper'; import { OsdService } from '../../../../shared/api/osd.service'; import { ConfirmationModalComponent } from '../../../../shared/components/confirmation-modal/confirmation-modal.component'; import { CriticalConfirmationModalComponent } from '../../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; @@ -78,7 +82,8 @@ describe('OsdListComponent', () => { providers: [ { provide: AuthStorageService, useValue: fakeAuthStorageService }, TableActionsComponent, - BsModalService + BsModalService, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts index bfa255662a4..1aadc0219eb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { Observable } from 'rxjs'; @@ -55,81 +56,87 @@ export class OsdListComponent implements OnInit { private authStorageService: AuthStorageService, private osdService: OsdService, private dimlessBinaryPipe: DimlessBinaryPipe, - private modalService: BsModalService + private modalService: BsModalService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().osd; this.tableActions = [ { - name: 'Scrub', + name: this.i18n('Scrub'), permission: 'update', icon: 'fa-stethoscope', click: () => this.scrubAction(false), disable: () => !this.hasOsdSelected }, { - name: 'Deep Scrub', + name: this.i18n('Deep Scrub'), permission: 'update', icon: 'fa-cog', click: () => this.scrubAction(true), disable: () => !this.hasOsdSelected }, { - name: 'Reweight', + name: this.i18n('Reweight'), permission: 'update', click: () => this.reweight(), disable: () => !this.hasOsdSelected, icon: 'fa-balance-scale' }, { - name: 'Mark Out', + name: this.i18n('Mark Out'), permission: 'update', - click: () => this.showConfirmationModal('out', this.osdService.markOut), + click: () => this.showConfirmationModal(this.i18n('out'), this.osdService.markOut), disable: () => this.isNotSelectedOrInState('out'), icon: 'fa-arrow-left' }, { - name: 'Mark In', + name: this.i18n('Mark In'), permission: 'update', - click: () => this.showConfirmationModal('in', this.osdService.markIn), + click: () => this.showConfirmationModal(this.i18n('in'), this.osdService.markIn), disable: () => this.isNotSelectedOrInState('in'), icon: 'fa-arrow-right' }, { - name: 'Mark Down', + name: this.i18n('Mark Down'), permission: 'update', - click: () => this.showConfirmationModal('down', this.osdService.markDown), + click: () => this.showConfirmationModal(this.i18n('down'), this.osdService.markDown), disable: () => this.isNotSelectedOrInState('down'), icon: 'fa-arrow-down' }, { - name: 'Mark Lost', + name: this.i18n('Mark Lost'), permission: 'delete', click: () => this.showCriticalConfirmationModal( - 'Mark', - 'OSD lost', - 'marked lost', + this.i18n('Mark'), + this.i18n('OSD lost'), + this.i18n('marked lost'), this.osdService.markLost ), disable: () => this.isNotSelectedOrInState('up'), icon: 'fa-unlink' }, { - name: 'Remove', + name: this.i18n('Remove'), permission: 'delete', click: () => - this.showCriticalConfirmationModal('Remove', 'OSD', 'removed', this.osdService.remove), + this.showCriticalConfirmationModal( + this.i18n('Remove'), + this.i18n('OSD'), + this.i18n('removed'), + this.osdService.remove + ), disable: () => this.isNotSelectedOrInState('up'), icon: 'fa-remove' }, { - name: 'Destroy', + name: this.i18n('Destroy'), permission: 'delete', click: () => this.showCriticalConfirmationModal( - 'destroy', - 'OSD', - 'destroyed', + this.i18n('destroy'), + this.i18n('OSD'), + this.i18n('destroyed'), this.osdService.destroy ), disable: () => this.isNotSelectedOrInState('up'), @@ -140,24 +147,32 @@ export class OsdListComponent implements OnInit { ngOnInit() { this.columns = [ - { prop: 'host.name', name: 'Host' }, - { prop: 'id', name: 'ID', cellTransformation: CellTemplate.bold }, - { prop: 'collectedStates', name: 'Status', cellTemplate: this.statusColor }, - { prop: 'stats.numpg', name: 'PGs' }, - { prop: 'stats.stat_bytes', name: 'Size', pipe: this.dimlessBinaryPipe }, - { name: 'Usage', cellTemplate: this.osdUsageTpl }, + { prop: 'host.name', name: this.i18n('Host') }, + { prop: 'id', name: this.i18n('ID'), cellTransformation: CellTemplate.bold }, + { prop: 'collectedStates', name: this.i18n('Status'), cellTemplate: this.statusColor }, + { prop: 'stats.numpg', name: this.i18n('PGs') }, + { prop: 'stats.stat_bytes', name: this.i18n('Size'), pipe: this.dimlessBinaryPipe }, + { name: this.i18n('Usage'), cellTemplate: this.osdUsageTpl }, { prop: 'stats_history.out_bytes', - name: 'Read bytes', + name: this.i18n('Read bytes'), cellTransformation: CellTemplate.sparkline }, { prop: 'stats_history.in_bytes', - name: 'Writes bytes', + name: this.i18n('Writes bytes'), cellTransformation: CellTemplate.sparkline }, - { prop: 'stats.op_r', name: 'Read ops', cellTransformation: CellTemplate.perSecond }, - { prop: 'stats.op_w', name: 'Write ops', cellTransformation: CellTemplate.perSecond } + { + prop: 'stats.op_r', + name: this.i18n('Read ops'), + cellTransformation: CellTemplate.perSecond + }, + { + prop: 'stats.op_w', + name: this.i18n('Write ops'), + cellTransformation: CellTemplate.perSecond + } ]; } @@ -236,8 +251,8 @@ export class OsdListComponent implements OnInit { showConfirmationModal(markAction: string, onSubmit: (id: number) => Observable) { this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState: { - titleText: `Mark OSD ${markAction}`, - buttonText: `Mark ${markAction}`, + titleText: this.i18n('Mark OSD {{markAction}}', { markAction: markAction }), + buttonText: this.i18n('Mark {{markAction}}', { markAction: markAction }), bodyTpl: this.markOsdConfirmationTpl, bodyContext: { markActionDescription: markAction diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.spec.ts index 5c6888062b4..1fc99668bcb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.spec.ts @@ -4,7 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { BsModalRef } from 'ngx-bootstrap/modal'; -import { configureTestBed } from '../../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper'; import { OsdService } from '../../../../shared/api/osd.service'; import { NotificationService } from '../../../../shared/services/notification.service'; import { OsdScrubModalComponent } from './osd-scrub-modal.component'; @@ -38,7 +38,8 @@ describe('OsdScrubModalComponent', () => { providers: [ BsModalRef, { provide: OsdService, useValue: fakeService }, - { provide: NotificationService, useValue: fakeService } + { provide: NotificationService, useValue: fakeService }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.ts index 98a367c763f..de76ea884e8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { OsdService } from '../../../../shared/api/osd.service'; @@ -20,7 +21,8 @@ export class OsdScrubModalComponent implements OnInit { constructor( public bsModalRef: BsModalRef, private osdService: OsdService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) {} ngOnInit() { @@ -36,7 +38,10 @@ export class OsdScrubModalComponent implements OnInit { this.notificationService.show( NotificationType.success, - `${operation} was initialized in the following OSD: ${id}` + this.i18n('{{operation}} was initialized in the following OSD: {{id}}', { + operation: operation, + id: id + }) ); this.bsModalRef.hide(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts index cfd808aaeb9..58cc5db7fd1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts @@ -6,7 +6,7 @@ import * as _ from 'lodash'; import { PopoverModule } from 'ngx-bootstrap/popover'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { DashboardService } from '../../../shared/api/dashboard.service'; import { SharedModule } from '../../../shared/shared.module'; import { LogColorPipe } from '../log-color.pipe'; @@ -50,7 +50,8 @@ describe('HealthComponent', () => { LogColorPipe, PgStatusPipe ], - schemas: [NO_ERRORS_SCHEMA] + schemas: [NO_ERRORS_SCHEMA], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts index 3362bde3da5..f2917f6ab62 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts @@ -1,6 +1,7 @@ import { ViewportScroller } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { DashboardService } from '../../../shared/api/dashboard.service'; @@ -16,7 +17,8 @@ export class HealthComponent implements OnInit, OnDestroy { constructor( private dashboardService: DashboardService, - public viewportScroller: ViewportScroller + public viewportScroller: ViewportScroller, + private i18n: I18n ) {} ngOnInit() { @@ -40,9 +42,9 @@ export class HealthComponent implements OnInit, OnDestroy { const ratioLabels = []; const ratioData = []; - ratioLabels.push('Writes'); + ratioLabels.push(this.i18n('Writes')); ratioData.push(this.contentData.client_perf.write_op_per_sec); - ratioLabels.push('Reads'); + ratioLabels.push(this.i18n('Reads')); ratioData.push(this.contentData.client_perf.read_op_per_sec); chart.dataset[0].data = ratioData; @@ -63,13 +65,16 @@ export class HealthComponent implements OnInit, OnDestroy { if (chart === 'doughnut') { chart.options.cutoutPercentage = 65; } - chart.labels = [`Used (${percentUsed}%)`, `Avail. (${percentAvailable}%)`]; + chart.labels = [ + `${this.i18n('Used')} (${percentUsed}%)`, + `${this.i18n('Avail.')} (${percentAvailable}%)` + ]; } preparePgStatus(chart, data) { - const pgCategoryClean = 'Clean'; + const pgCategoryClean = this.i18n('Clean'); const pgCategoryCleanStates = ['active', 'clean']; - const pgCategoryWarning = 'Warning'; + const pgCategoryWarning = this.i18n('Warning'); const pgCategoryWarningStates = [ 'backfill_toofull', 'backfill_unfound', @@ -83,8 +88,8 @@ export class HealthComponent implements OnInit, OnDestroy { 'stale', 'undersized' ]; - const pgCategoryUnknown = 'Unknown'; - const pgCategoryWorking = 'Working'; + const pgCategoryUnknown = this.i18n('Unknown'); + const pgCategoryWorking = this.i18n('Working'); const pgCategoryWorkingStates = [ 'activating', 'backfill_wait', diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.spec.ts index bbf33b5ac9a..e8f004e9faa 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.spec.ts @@ -1,7 +1,18 @@ +import { TestBed } from '@angular/core/testing'; + +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { MdsSummaryPipe } from './mds-summary.pipe'; describe('MdsSummaryPipe', () => { - const pipe = new MdsSummaryPipe(); + let pipe: MdsSummaryPipe; + + configureTestBed({ + providers: [MdsSummaryPipe, i18nProviders] + }); + + beforeEach(() => { + pipe = TestBed.get(MdsSummaryPipe); + }); it('create an instance', () => { expect(pipe).toBeTruthy(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.ts index 9e6eeca6e8a..7c2785111e7 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mds-summary.pipe.ts @@ -1,10 +1,14 @@ import { Pipe, PipeTransform } from '@angular/core'; + +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; @Pipe({ name: 'mdsSummary' }) export class MdsSummaryPipe implements PipeTransform { + constructor(private i18n: I18n) {} + transform(value: any, args?: any): any { if (!value) { return ''; @@ -18,9 +22,9 @@ export class MdsSummaryPipe implements PipeTransform { }); if (value.standbys && !value.filesystems) { - return standbys + ', no filesystems'; + return standbys + ', ' + this.i18n('no filesystems'); } else if (value.filesystems.length === 0) { - return 'no filesystems'; + return this.i18n('no filesystems'); } else { _.each(value.filesystems, (fs, i) => { _.each(fs.mdsmap.info, (mds, j) => { @@ -32,7 +36,9 @@ export class MdsSummaryPipe implements PipeTransform { }); }); - return active + ' active, ' + (standbys + standbyReplay) + ' standby'; + return `${active} ${this.i18n('active')}, ${standbys + standbyReplay} ${this.i18n( + 'standby' + )}`; } } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.spec.ts index 0800019941b..754511dd5ae 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.spec.ts @@ -1,7 +1,19 @@ +import { TestBed } from '@angular/core/testing'; + +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; + import { MgrSummaryPipe } from './mgr-summary.pipe'; describe('MgrSummaryPipe', () => { - const pipe = new MgrSummaryPipe(); + let pipe: MgrSummaryPipe; + + configureTestBed({ + providers: [MgrSummaryPipe, i18nProviders] + }); + + beforeEach(() => { + pipe = TestBed.get(MgrSummaryPipe); + }); it('create an instance', () => { expect(pipe).toBeTruthy(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.ts index cf793e66e47..f55f0c304e9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mgr-summary.pipe.ts @@ -1,10 +1,14 @@ import { Pipe, PipeTransform } from '@angular/core'; + +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; @Pipe({ name: 'mgrSummary' }) export class MgrSummaryPipe implements PipeTransform { + constructor(private i18n: I18n) {} + transform(value: any, args?: any): any { if (!value) { return ''; @@ -14,7 +18,7 @@ export class MgrSummaryPipe implements PipeTransform { result += _.isUndefined(value.active_name) ? 'n/a' : value.active_name; if (value.standbys.length) { - result += ', ' + value.standbys.length + ' standbys'; + result += ', ' + value.standbys.length + ' ' + this.i18n('standbys'); } return result; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.spec.ts index 49f23bcba06..9d193a5e0f6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.spec.ts @@ -1,7 +1,18 @@ +import { TestBed } from '@angular/core/testing'; + +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { MonSummaryPipe } from './mon-summary.pipe'; describe('MonSummaryPipe', () => { - const pipe = new MonSummaryPipe(); + let pipe: MonSummaryPipe; + + configureTestBed({ + providers: [MonSummaryPipe, i18nProviders] + }); + + beforeEach(() => { + pipe = TestBed.get(MonSummaryPipe); + }); it('create an instance', () => { expect(pipe).toBeTruthy(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.ts index 6877e2247c7..48949a04fa8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/mon-summary.pipe.ts @@ -1,17 +1,21 @@ import { Pipe, PipeTransform } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + @Pipe({ name: 'monSummary' }) export class MonSummaryPipe implements PipeTransform { + constructor(private i18n: I18n) {} + transform(value: any, args?: any): any { if (!value) { return ''; } - let result = value.monmap.mons.length.toString() + ' (quorum '; - result += value.quorum.join(', '); - result += ')'; + const result = `${value.monmap.mons.length.toString()} (${this.i18n( + 'quorum' + )} ${value.quorum.join(', ')})`; return result; } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.spec.ts index 92119691bf5..6332017dd71 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.spec.ts @@ -1,7 +1,17 @@ +import { TestBed } from '@angular/core/testing'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { OsdSummaryPipe } from './osd-summary.pipe'; describe('OsdSummaryPipe', () => { - const pipe = new OsdSummaryPipe(); + let pipe: OsdSummaryPipe; + + configureTestBed({ + providers: [OsdSummaryPipe, i18nProviders] + }); + + beforeEach(() => { + pipe = TestBed.get(OsdSummaryPipe); + }); it('create an instance', () => { expect(pipe).toBeTruthy(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.ts index ad34e87bc67..b6a444be673 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/osd-summary.pipe.ts @@ -1,10 +1,14 @@ import { Pipe, PipeTransform } from '@angular/core'; + +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; @Pipe({ name: 'osdSummary' }) export class OsdSummaryPipe implements PipeTransform { + constructor(private i18n: I18n) {} + transform(value: any, args?: any): any { if (!value) { return ''; @@ -23,7 +27,7 @@ export class OsdSummaryPipe implements PipeTransform { const osdSummary = [ { - content: `${value.osds.length} total`, + content: `${value.osds.length} ${this.i18n('total')}`, class: '' } ]; @@ -32,7 +36,7 @@ export class OsdSummaryPipe implements PipeTransform { class: 'card-text-line-break' }); osdSummary.push({ - content: `${upCount} up, ${inCount} in`, + content: `${upCount} ${this.i18n('up')}, ${inCount} ${this.i18n('in')}`, class: '' }); @@ -44,9 +48,9 @@ export class OsdSummaryPipe implements PipeTransform { class: 'card-text-line-break' }); - const downText = downCount > 0 ? `${downCount} down` : ''; + const downText = downCount > 0 ? `${downCount} ${this.i18n('down')}` : ''; const separator = downCount > 0 && outCount > 0 ? ', ' : ''; - const outText = outCount > 0 ? `${outCount} out` : ''; + const outText = outCount > 0 ? `${outCount} ${this.i18n('out')}` : ''; osdSummary.push({ content: `${downText}${separator}${outText}`, class: 'card-text-error' diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/performance-counter/performance-counter.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/performance-counter/performance-counter.component.spec.ts index d725a61b619..233599bed42 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/performance-counter/performance-counter.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/performance-counter/performance-counter.component.spec.ts @@ -2,7 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { TablePerformanceCounterComponent } from '../table-performance-counter/table-performance-counter.component'; import { PerformanceCounterComponent } from './performance-counter.component'; @@ -13,7 +13,8 @@ describe('PerformanceCounterComponent', () => { configureTestBed({ declarations: [PerformanceCounterComponent, TablePerformanceCounterComponent], - imports: [RouterTestingModule, SharedModule, HttpClientTestingModule] + imports: [RouterTestingModule, SharedModule, HttpClientTestingModule], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.spec.ts index 4e1cd078968..4a219d8b103 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.spec.ts @@ -1,7 +1,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { AppModule } from '../../../app.module'; import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context'; import { TablePerformanceCounterComponent } from './table-performance-counter.component'; @@ -12,7 +12,8 @@ describe('TablePerformanceCounterComponent', () => { let httpTesting: HttpTestingController; configureTestBed({ - imports: [AppModule, HttpClientTestingModule] + imports: [AppModule, HttpClientTestingModule], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.ts index 704afb066c3..3d5979582d1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/performance-counter/table-performance-counter/table-performance-counter.component.ts @@ -1,5 +1,7 @@ import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { PerformanceCounterService } from '../../../shared/api/performance-counter.service'; import { CdTableColumn } from '../../../shared/models/cd-table-column'; import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context'; @@ -31,22 +33,22 @@ export class TablePerformanceCounterComponent implements OnInit { @Input() serviceId: string; - constructor(private performanceCounterService: PerformanceCounterService) {} + constructor(private performanceCounterService: PerformanceCounterService, private i18n: I18n) {} ngOnInit() { this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'name', flexGrow: 1 }, { - name: 'Description', + name: this.i18n('Description'), prop: 'description', flexGrow: 1 }, { - name: 'Value', + name: this.i18n('Value'), cellTemplate: this.valueTpl, flexGrow: 1 } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-tooltips.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-tooltips.ts index c74a6bd3715..358354dee94 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-tooltips.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-tooltips.ts @@ -1,4 +1,5 @@ export class ErasureCodeProfileFormTooltips { + // TODO: I18N // Copied from /srv/cephmgr/ceph-dev/doc/rados/operations/erasure-code.*.rst k = `Each object is split in data-chunks parts, each stored on a different OSD.`; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.spec.ts index b5819e9c0ab..a8a998c3cec 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.spec.ts @@ -7,7 +7,7 @@ import { ToastModule } from 'ng2-toastr'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { of } from 'rxjs'; -import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper, i18nProviders } from '../../../../testing/unit-test-helper'; import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service'; import { ErasureCodeProfile } from '../../../shared/models/erasure-code-profile'; import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; @@ -23,7 +23,7 @@ describe('ErasureCodeProfileFormComponent', () => { configureTestBed({ imports: [HttpClientTestingModule, RouterTestingModule, ToastModule.forRoot(), PoolModule], - providers: [ErasureCodeProfileService, BsModalRef] + providers: [ErasureCodeProfileService, BsModalRef, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form-data.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form-data.ts index c87f2c059e2..0c0e1390ea1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form-data.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form-data.ts @@ -1,35 +1,43 @@ import { Validators } from '@angular/forms'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { SelectBadgesMessages } from '../../../shared/components/select-badges/select-badges-messages.model'; import { SelectBadgesOption } from '../../../shared/components/select-badges/select-badges-option.model'; import { Pool } from '../pool'; export class PoolFormData { - poolTypes = ['erasure', 'replicated']; + poolTypes: string[]; erasureInfo = false; crushInfo = false; - applications = { - selected: [], - available: [ - new SelectBadgesOption(false, 'cephfs', ''), - new SelectBadgesOption(false, 'rbd', ''), - new SelectBadgesOption(false, 'rgw', '') - ], - validators: [Validators.pattern('[A-Za-z0-9_]+'), Validators.maxLength(128)], - messages: new SelectBadgesMessages({ - empty: 'No applications added', - selectionLimit: { - text: 'Applications limit reached', - tooltip: 'A pool can only have up to four applications definitions.' - }, - customValidations: { - pattern: `Allowed characters '_a-zA-Z0-9'`, - maxlength: 'Maximum length is 128 characters' - }, - filter: 'Filter or add applications', - add: 'Add application' - }) - }; + applications: any; + + constructor(i18n: I18n) { + this.poolTypes = ['erasure', 'replicated']; + this.applications = { + selected: [], + available: [ + new SelectBadgesOption(false, 'cephfs', ''), + new SelectBadgesOption(false, 'rbd', ''), + new SelectBadgesOption(false, 'rgw', '') + ], + validators: [Validators.pattern('[A-Za-z0-9_]+'), Validators.maxLength(128)], + messages: new SelectBadgesMessages({ + empty: i18n('No applications added'), + selectionLimit: { + text: i18n('Applications limit reached'), + tooltip: i18n('A pool can only have up to four applications definitions.') + }, + customValidations: { + pattern: i18n(`Allowed characters '_a-zA-Z0-9'`), + maxlength: i18n('Maximum length is 128 characters') + }, + filter: i18n('Filter or add applications'), + add: i18n('Add application') + }) + }; + } + pgs = 1; pool: Pool; // Only available during edit mode } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts index 5770d240f5e..6b463693b0a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts @@ -10,7 +10,7 @@ import { BsModalService } from 'ngx-bootstrap/modal'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { of } from 'rxjs'; -import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper, i18nProviders } from '../../../../testing/unit-test-helper'; import { NotFoundComponent } from '../../../core/not-found/not-found.component'; import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service'; import { PoolService } from '../../../shared/api/pool.service'; @@ -134,7 +134,8 @@ describe('PoolFormComponent', () => { providers: [ ErasureCodeProfileService, SelectBadgesComponent, - { provide: ActivatedRoute, useValue: { params: of({ name: 'somePoolName' }) } } + { provide: ActivatedRoute, useValue: { params: of({ name: 'somePoolName' }) } }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts index a43198ff222..d951e80789f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalService } from 'ngx-bootstrap/modal'; import { forkJoin, Subscription } from 'rxjs'; @@ -38,7 +39,7 @@ export class PoolFormComponent implements OnInit { info: PoolFormInfo; routeParamsSubscribe: any; editing = false; - data = new PoolFormData(); + data = new PoolFormData(this.i18n); externalPgChange = false; private modalSubscription: Subscription; current = { @@ -55,7 +56,8 @@ export class PoolFormComponent implements OnInit { private formatter: FormatterService, private bsModalService: BsModalService, private taskWrapper: TaskWrapperService, - private ecpService: ErasureCodeProfileService + private ecpService: ErasureCodeProfileService, + private i18n: I18n ) { this.editing = this.router.url.startsWith('/pool/edit'); this.authenticate(); @@ -453,7 +455,7 @@ export class PoolFormComponent implements OnInit { this.modalSubscription = this.modalService.onHide.subscribe(() => this.reloadECPs()); this.modalService.show(CriticalConfirmationModalComponent, { initialState: { - itemDescription: 'erasure code profile', + itemDescription: this.i18n('erasure code profile'), submitActionObservable: () => this.taskWrapper.wrapTaskAroundCall({ task: new FinishedTask('ecp/delete', { name: name }), diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts index ee8f6c54075..52c6674bdac 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts @@ -7,7 +7,7 @@ import { BsModalService } from 'ngx-bootstrap/modal'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { PoolService } from '../../../shared/api/pool.service'; import { DeletionModalComponent } from '../../../shared/components/deletion-modal/deletion-modal.component'; import { ExecutingTask } from '../../../shared/models/executing-task'; @@ -30,7 +30,8 @@ describe('PoolListComponent', () => { RouterTestingModule, TabsModule.forRoot(), HttpClientTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts index cad9b85a1e1..83b9774d43b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { PoolService } from '../../../shared/api/pool.service'; @@ -42,67 +43,73 @@ export class PoolListComponent implements OnInit { private taskWrapper: TaskWrapperService, private authStorageService: AuthStorageService, private taskListService: TaskListService, - private modalService: BsModalService + private modalService: BsModalService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().pool; this.tableActions = [ - { permission: 'create', icon: 'fa-plus', routerLink: () => '/pool/add', name: 'Add' }, + { + permission: 'create', + icon: 'fa-plus', + routerLink: () => '/pool/add', + name: this.i18n('Add') + }, { permission: 'update', icon: 'fa-pencil', routerLink: () => '/pool/edit/' + this.selection.first().pool_name, - name: 'Edit' + name: this.i18n('Edit') }, { permission: 'delete', icon: 'fa-trash-o', click: () => this.deletePoolModal(), - name: 'Delete' + name: this.i18n('Delete') } ]; this.columns = [ { prop: 'pool_name', - name: 'Name', + name: this.i18n('Name'), flexGrow: 3, cellTransformation: CellTemplate.executing }, { prop: 'type', - name: 'Type', + name: this.i18n('Type'), flexGrow: 2 }, { prop: 'application_metadata', - name: 'Applications', + name: this.i18n('Applications'), flexGrow: 3 }, { prop: 'pg_placement_num', - name: 'Placement Groups', + name: this.i18n('Placement Groups'), flexGrow: 1, cellClass: 'text-right' }, { prop: 'size', - name: 'Replica Size', + name: this.i18n('Replica Size'), flexGrow: 1, cellClass: 'text-right' }, { prop: 'last_change', - name: 'Last Change', + name: this.i18n('Last Change'), flexGrow: 1, cellClass: 'text-right' }, { prop: 'erasure_code_profile', - name: 'Erasure Coded Profile', + name: this.i18n('Erasure Coded Profile'), flexGrow: 2 }, { prop: 'crush_rule', - name: 'Crush Ruleset', + name: this.i18n('Crush Ruleset'), flexGrow: 2 } ]; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.spec.ts index 75941b9e30b..565caab1563 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.spec.ts @@ -2,7 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { Rgw501Component } from './rgw-501.component'; @@ -12,7 +12,8 @@ describe('Rgw501Component', () => { configureTestBed({ declarations: [Rgw501Component], - imports: [HttpClientTestingModule, RouterTestingModule, SharedModule] + imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.spec.ts index 60f9e0c1327..c6bb981d0a3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.spec.ts @@ -6,7 +6,11 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ModalModule } from 'ngx-bootstrap/modal'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component'; import { SharedModule } from '../../../shared/shared.module'; import { RgwBucketDetailsComponent } from '../rgw-bucket-details/rgw-bucket-details.component'; @@ -24,7 +28,8 @@ describe('RgwBucketListComponent', () => { SharedModule, TabsModule.forRoot(), HttpClientTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.ts index 170835f05db..3c4e8ce0547 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.ts @@ -1,5 +1,6 @@ import { Component, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalService } from 'ngx-bootstrap/modal'; import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs'; @@ -31,17 +32,18 @@ export class RgwBucketListComponent { constructor( private authStorageService: AuthStorageService, private rgwBucketService: RgwBucketService, - private bsModalService: BsModalService + private bsModalService: BsModalService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().rgw; this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'bucket', flexGrow: 1 }, { - name: 'Owner', + name: this.i18n('Owner'), prop: 'owner', flexGrow: 1 } @@ -52,19 +54,19 @@ export class RgwBucketListComponent { permission: 'create', icon: 'fa-plus', routerLink: () => '/rgw/bucket/add', - name: 'Add' + name: this.i18n('Add') }; const editAction: CdTableAction = { permission: 'update', icon: 'fa-pencil', routerLink: () => `/rgw/bucket/edit/${getBucketUri()}`, - name: 'Edit' + name: this.i18n('Edit') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', click: () => this.deleteAction(), - name: 'Delete' + name: this.i18n('Delete') }; this.tableActions = [addAction, editAction, deleteAction]; } @@ -87,7 +89,9 @@ export class RgwBucketListComponent { deleteAction() { this.bsModalService.show(CriticalConfirmationModalComponent, { initialState: { - itemDescription: this.selection.hasSingleSelection ? 'bucket' : 'buckets', + itemDescription: this.selection.hasSingleSelection + ? this.i18n('bucket') + : this.i18n('buckets'), submitActionObservable: () => { return new Observable((observer: Subscriber) => { // Delete all selected data table rows. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts index cc1b43c39d8..65b7102c869 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts @@ -4,7 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { PerformanceCounterModule } from '../../performance-counter/performance-counter.module'; import { RgwDaemonDetailsComponent } from '../rgw-daemon-details/rgw-daemon-details.component'; @@ -22,7 +22,8 @@ describe('RgwDaemonListComponent', () => { PerformanceCounterModule, SharedModule, RouterTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts index 281421f7886..d0eaaac9d43 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts @@ -1,5 +1,7 @@ import { Component } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { RgwDaemonService } from '../../../shared/api/rgw-daemon.service'; import { CdTableColumn } from '../../../shared/models/cd-table-column'; import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context'; @@ -18,21 +20,22 @@ export class RgwDaemonListComponent { constructor( private rgwDaemonService: RgwDaemonService, - cephShortVersionPipe: CephShortVersionPipe + cephShortVersionPipe: CephShortVersionPipe, + private i18n: I18n ) { this.columns = [ { - name: 'ID', + name: this.i18n('ID'), prop: 'id', flexGrow: 2 }, { - name: 'Hostname', + name: this.i18n('Hostname'), prop: 'server_hostname', flexGrow: 2 }, { - name: 'Version', + name: this.i18n('Version'), prop: 'version', flexGrow: 1, pipe: cephShortVersionPipe diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.spec.ts index 825b6920363..d5afbc5285a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.spec.ts @@ -4,7 +4,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { BsModalService } from 'ngx-bootstrap/modal'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { SharedModule } from '../../../shared/shared.module'; import { RgwUserDetailsComponent } from './rgw-user-details.component'; @@ -16,7 +16,7 @@ describe('RgwUserDetailsComponent', () => { configureTestBed({ declarations: [RgwUserDetailsComponent], imports: [HttpClientTestingModule, SharedModule, TabsModule.forRoot()], - providers: [BsModalService] + providers: [BsModalService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.ts index e3180651504..108efc63b9f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-details/rgw-user-details.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalService } from 'ngx-bootstrap/modal'; @@ -33,17 +34,21 @@ export class RgwUserDetailsComponent implements OnChanges, OnInit { keysColumns: CdTableColumn[] = []; keysSelection: CdTableSelection = new CdTableSelection(); - constructor(private rgwUserService: RgwUserService, private bsModalService: BsModalService) {} + constructor( + private rgwUserService: RgwUserService, + private bsModalService: BsModalService, + private i18n: I18n + ) {} ngOnInit() { this.keysColumns = [ { - name: 'Username', + name: this.i18n('Username'), prop: 'username', flexGrow: 1 }, { - name: 'Type', + name: this.i18n('Type'), prop: 'type', flexGrow: 1 } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.spec.ts index c42c10ec54f..8f05cab50aa 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.spec.ts @@ -6,7 +6,11 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ModalModule } from 'ngx-bootstrap/modal'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component'; import { SharedModule } from '../../../shared/shared.module'; import { RgwUserListComponent } from './rgw-user-list.component'; @@ -18,7 +22,8 @@ describe('RgwUserListComponent', () => { configureTestBed({ declarations: [RgwUserListComponent], imports: [RouterTestingModule, HttpClientTestingModule, ModalModule.forRoot(), SharedModule], - schemas: [NO_ERRORS_SCHEMA] + schemas: [NO_ERRORS_SCHEMA], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.ts index 29397ebdb96..2dacb8390c5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-list/rgw-user-list.component.ts @@ -1,5 +1,6 @@ import { Component, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalService } from 'ngx-bootstrap/modal'; import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs'; @@ -32,33 +33,34 @@ export class RgwUserListComponent { constructor( private authStorageService: AuthStorageService, private rgwUserService: RgwUserService, - private bsModalService: BsModalService + private bsModalService: BsModalService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().rgw; this.columns = [ { - name: 'Username', + name: this.i18n('Username'), prop: 'user_id', flexGrow: 1 }, { - name: 'Full name', + name: this.i18n('Full name'), prop: 'display_name', flexGrow: 1 }, { - name: 'Email address', + name: this.i18n('Email address'), prop: 'email', flexGrow: 1 }, { - name: 'Suspended', + name: this.i18n('Suspended'), prop: 'suspended', flexGrow: 1, cellTransformation: CellTemplate.checkIcon }, { - name: 'Max. buckets', + name: this.i18n('Max. buckets'), prop: 'max_buckets', flexGrow: 1 } @@ -68,19 +70,19 @@ export class RgwUserListComponent { permission: 'create', icon: 'fa-plus', routerLink: () => '/rgw/user/add', - name: 'Add' + name: this.i18n('Add') }; const editAction: CdTableAction = { permission: 'update', icon: 'fa-pencil', routerLink: () => `/rgw/user/edit/${getUserUri()}`, - name: 'Edit' + name: this.i18n('Edit') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', click: () => this.deleteAction(), - name: 'Delete' + name: this.i18n('Delete') }; this.tableActions = [addAction, editAction, deleteAction]; } @@ -103,7 +105,7 @@ export class RgwUserListComponent { deleteAction() { this.bsModalService.show(CriticalConfirmationModalComponent, { initialState: { - itemDescription: this.selection.hasSingleSelection ? 'user' : 'users', + itemDescription: this.selection.hasSingleSelection ? this.i18n('user') : this.i18n('users'), submitActionObservable: (): Observable => { return new Observable((observer: Subscriber) => { // Delete all selected data table rows. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.spec.ts index 28c0f68ead4..71ec6fbf7e1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.spec.ts @@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { SharedModule } from '../../../shared/shared.module'; import { RoleDetailsComponent } from './role-details.component'; @@ -22,7 +22,8 @@ describe('RoleDetailsComponent', () => { RouterTestingModule, HttpClientTestingModule ], - declarations: [RoleDetailsComponent] + declarations: [RoleDetailsComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.ts index a81f4cbda1c..4a8e0268775 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-details/role-details.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { CellTemplate } from '../../../shared/enum/cell-template.enum'; @@ -21,39 +22,39 @@ export class RoleDetailsComponent implements OnChanges, OnInit { columns: CdTableColumn[]; scopes_permissions: Array = []; - constructor() {} + constructor(private i18n: I18n) {} ngOnInit() { this.columns = [ { prop: 'scope', - name: 'Scope', + name: this.i18n('Scope'), flexGrow: 2 }, { prop: 'read', - name: 'Read', + name: this.i18n('Read'), flexGrow: 1, cellClass: 'text-center', cellTransformation: CellTemplate.checkIcon }, { prop: 'create', - name: 'Create', + name: this.i18n('Create'), flexGrow: 1, cellClass: 'text-center', cellTransformation: CellTemplate.checkIcon }, { prop: 'update', - name: 'Update', + name: this.i18n('Update'), flexGrow: 1, cellClass: 'text-center', cellTransformation: CellTemplate.checkIcon }, { prop: 'delete', - name: 'Delete', + name: this.i18n('Delete'), flexGrow: 1, cellClass: 'text-center', cellTransformation: CellTemplate.checkIcon diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts index eb2f1caab20..b80fa441176 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts @@ -8,7 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { of } from 'rxjs'; -import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper, i18nProviders } from '../../../../testing/unit-test-helper'; import { RoleService } from '../../../shared/api/role.service'; import { ScopeService } from '../../../shared/api/scope.service'; import { CdFormGroup } from '../../../shared/forms/cd-form-group'; @@ -40,7 +40,8 @@ describe('RoleFormComponent', () => { ToastModule.forRoot(), SharedModule ], - declarations: [RoleFormComponent, FakeComponent] + declarations: [RoleFormComponent, FakeComponent], + providers: i18nProviders }, true ); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.ts index c8dcc717664..a1b02c7be2b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { forkJoin as observableForkJoin } from 'rxjs'; @@ -46,7 +47,8 @@ export class RoleFormComponent implements OnInit { private router: Router, private roleService: RoleService, private scopeService: ScopeService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) { this.createForm(); this.listenToChanges(); @@ -67,14 +69,14 @@ export class RoleFormComponent implements OnInit { this.columns = [ { prop: 'scope', - name: 'All', + name: this.i18n('All'), flexGrow: 2, cellTemplate: this.cellScopeCheckboxTpl, headerTemplate: this.headerPermissionCheckboxTpl }, { prop: 'read', - name: 'Read', + name: this.i18n('Read'), flexGrow: 1, cellClass: 'text-center', cellTemplate: this.cellPermissionCheckboxTpl, @@ -82,7 +84,7 @@ export class RoleFormComponent implements OnInit { }, { prop: 'create', - name: 'Create', + name: this.i18n('Create'), flexGrow: 1, cellClass: 'text-center', cellTemplate: this.cellPermissionCheckboxTpl, @@ -90,7 +92,7 @@ export class RoleFormComponent implements OnInit { }, { prop: 'update', - name: 'Update', + name: this.i18n('Update'), flexGrow: 1, cellClass: 'text-center', cellTemplate: this.cellPermissionCheckboxTpl, @@ -98,7 +100,7 @@ export class RoleFormComponent implements OnInit { }, { prop: 'delete', - name: 'Delete', + name: this.i18n('Delete'), flexGrow: 1, cellClass: 'text-center', cellTemplate: this.cellPermissionCheckboxTpl, @@ -267,7 +269,7 @@ export class RoleFormComponent implements OnInit { () => { this.notificationService.show( NotificationType.success, - `Created role '${roleFormModel.name}'` + this.i18n(`Created role '{{role_name}}'`, { role_name: roleFormModel.name }) ); this.router.navigate(['/user-management/roles']); }, @@ -283,7 +285,7 @@ export class RoleFormComponent implements OnInit { () => { this.notificationService.show( NotificationType.success, - `Updated role '${roleFormModel.name}'` + this.i18n(`Updated role '{{role_name}}'`, { role_name: roleFormModel.name }) ); this.router.navigate(['/user-management/roles']); }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.spec.ts index 4a2a7d31733..58c0c17a8ab 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.spec.ts @@ -6,7 +6,11 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component'; import { SharedModule } from '../../../shared/shared.module'; import { RoleDetailsComponent } from '../role-details/role-details.component'; @@ -25,7 +29,8 @@ describe('RoleListComponent', () => { TabsModule.forRoot(), RouterTestingModule, HttpClientTestingModule - ] + ], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.ts index 2f1836408ef..007f4bbbea8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-list/role-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { forkJoin } from 'rxjs'; @@ -37,14 +38,15 @@ export class RoleListComponent implements OnInit { private emptyPipe: EmptyPipe, private authStorageService: AuthStorageService, private modalService: BsModalService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().user; const addAction: CdTableAction = { permission: 'create', icon: 'fa-plus', routerLink: () => '/user-management/roles/add', - name: 'Add' + name: this.i18n('Add') }; const editAction: CdTableAction = { permission: 'update', @@ -52,14 +54,14 @@ export class RoleListComponent implements OnInit { disable: () => !this.selection.hasSingleSelection || this.selection.first().system, routerLink: () => this.selection.first() && `/user-management/roles/edit/${this.selection.first().name}`, - name: 'Edit' + name: this.i18n('Edit') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', disable: () => !this.selection.hasSingleSelection || this.selection.first().system, click: () => this.deleteRoleModal(), - name: 'Delete' + name: this.i18n('Delete') }; this.tableActions = [addAction, editAction, deleteAction]; } @@ -67,18 +69,18 @@ export class RoleListComponent implements OnInit { ngOnInit() { this.columns = [ { - name: 'Name', + name: this.i18n('Name'), prop: 'name', flexGrow: 3 }, { - name: 'Description', + name: this.i18n('Description'), prop: 'description', flexGrow: 5, pipe: this.emptyPipe }, { - name: 'System Role', + name: this.i18n('System Role'), prop: 'system', cellClass: 'text-center', flexGrow: 1, @@ -105,7 +107,10 @@ export class RoleListComponent implements OnInit { () => { this.getRoles(); this.modalRef.hide(); - this.notificationService.show(NotificationType.success, `Deleted role '${role}'`); + this.notificationService.show( + NotificationType.success, + this.i18n(`Deleted role '{{role_name}}'`, { role_name: role }) + ); }, () => { this.modalRef.content.stopLoadingSpinner(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts index 690a58e4979..47276a8f561 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts @@ -9,7 +9,7 @@ import { ToastModule } from 'ng2-toastr'; import { BsModalService } from 'ngx-bootstrap/modal'; import { of } from 'rxjs'; -import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper, i18nProviders } from '../../../../testing/unit-test-helper'; import { RoleService } from '../../../shared/api/role.service'; import { UserService } from '../../../shared/api/user.service'; import { ComponentsModule } from '../../../shared/components/components.module'; @@ -50,7 +50,8 @@ describe('UserFormComponent', () => { ToastModule.forRoot(), SharedModule ], - declarations: [UserFormComponent, FakeComponent] + declarations: [UserFormComponent, FakeComponent], + providers: i18nProviders }, true ); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts index 2b1530d8457..bc0da5fd27a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; @@ -46,7 +47,8 @@ export class UserFormComponent implements OnInit { private modalService: BsModalService, private roleService: RoleService, private userService: UserService, - private notificationService: NotificationService + private notificationService: NotificationService, + private i18n: I18n ) { this.createForm(); } @@ -123,7 +125,7 @@ export class UserFormComponent implements OnInit { () => { this.notificationService.show( NotificationType.success, - `Created user "${userFormModel.username}"` + this.i18n('Created user "{{username}}"', { username: userFormModel.username }) ); this.router.navigate(['/user-management/users']); }, @@ -136,8 +138,8 @@ export class UserFormComponent implements OnInit { editAction() { if (this.isUserRemovingNeededRolePermissions()) { const initialState = { - titleText: 'Update user', - buttonText: 'Continue', + titleText: this.i18n('Update user'), + buttonText: this.i18n('Continue'), bodyTpl: this.removeSelfUserReadUpdatePermissionTpl, onSubmit: () => { this.modalRef.hide(); @@ -192,13 +194,13 @@ export class UserFormComponent implements OnInit { this.authService.logout(() => { this.notificationService.show( NotificationType.info, - 'You were automatically logged out because your roles have been changed.' + this.i18n('You were automatically logged out because your roles have been changed.') ); }); } else { this.notificationService.show( NotificationType.success, - `Updated user "${userFormModel.username}"` + this.i18n('Updated user "{{username}}"', { username: userFormModel.username }) ); this.router.navigate(['/user-management/users']); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.spec.ts index 7c02dac5994..fcee4c3bd6e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.spec.ts @@ -6,7 +6,11 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { TabsModule } from 'ngx-bootstrap/tabs'; -import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper'; +import { + configureTestBed, + i18nProviders, + PermissionHelper +} from '../../../../testing/unit-test-helper'; import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component'; import { SharedModule } from '../../../shared/shared.module'; import { UserTabsComponent } from '../user-tabs/user-tabs.component'; @@ -24,7 +28,8 @@ describe('UserListComponent', () => { RouterTestingModule, HttpClientTestingModule ], - declarations: [UserListComponent, UserTabsComponent] + declarations: [UserListComponent, UserTabsComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.ts index 1152c7e795d..8ef93957cd2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-list/user-list.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { UserService } from '../../../shared/api/user.service'; @@ -35,27 +36,28 @@ export class UserListComponent implements OnInit { private emptyPipe: EmptyPipe, private modalService: BsModalService, private notificationService: NotificationService, - private authStorageService: AuthStorageService + private authStorageService: AuthStorageService, + private i18n: I18n ) { this.permission = this.authStorageService.getPermissions().user; const addAction: CdTableAction = { permission: 'create', icon: 'fa-plus', routerLink: () => '/user-management/users/add', - name: 'Add' + name: this.i18n('Add') }; const editAction: CdTableAction = { permission: 'update', icon: 'fa-pencil', routerLink: () => this.selection.first() && `/user-management/users/edit/${this.selection.first().username}`, - name: 'Edit' + name: this.i18n('Edit') }; const deleteAction: CdTableAction = { permission: 'delete', icon: 'fa-times', click: () => this.deleteUserModal(), - name: 'Delete' + name: this.i18n('Delete') }; this.tableActions = [addAction, editAction, deleteAction]; } @@ -63,24 +65,24 @@ export class UserListComponent implements OnInit { ngOnInit() { this.columns = [ { - name: 'Username', + name: this.i18n('Username'), prop: 'username', flexGrow: 1 }, { - name: 'Name', + name: this.i18n('Name'), prop: 'name', flexGrow: 1, pipe: this.emptyPipe }, { - name: 'Email', + name: this.i18n('Email'), prop: 'email', flexGrow: 1, pipe: this.emptyPipe }, { - name: 'Roles', + name: this.i18n('Roles'), prop: 'roles', flexGrow: 1, cellTemplate: this.userRolesTpl @@ -103,7 +105,10 @@ export class UserListComponent implements OnInit { () => { this.getUsers(); this.modalRef.hide(); - this.notificationService.show(NotificationType.success, `Deleted user "${username}"`); + this.notificationService.show( + NotificationType.success, + this.i18n('Deleted user "{{username}}"', { username: username }) + ); }, () => { this.modalRef.content.stopLoadingSpinner(); @@ -117,8 +122,8 @@ export class UserListComponent implements OnInit { if (sessionUsername === username) { this.notificationService.show( NotificationType.error, - `Failed to delete user "${username}"`, - `You are currently logged in as "${username}".` + this.i18n('Failed to delete user "{{username}}"', { username: username }), + this.i18n('You are currently logged in as "{{username}}".', { username: username }) ); return; } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts index 6792cf8e985..29dc3154689 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { AppModule } from '../../../app.module'; import { NavigationComponent } from './navigation.component'; @@ -9,7 +9,8 @@ describe('NavigationComponent', () => { let fixture: ComponentFixture; configureTestBed({ - imports: [AppModule] + imports: [AppModule], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts index 0c1706d7f9d..5b081d8d720 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/notifications/notifications.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ToastModule } from 'ng2-toastr'; import { PopoverModule } from 'ngx-bootstrap/popover'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SharedModule } from '../../../shared/shared.module'; import { NotificationsComponent } from './notifications.component'; @@ -13,7 +13,8 @@ describe('NotificationsComponent', () => { configureTestBed({ imports: [PopoverModule.forRoot(), SharedModule, ToastModule.forRoot()], - declarations: [NotificationsComponent] + declarations: [NotificationsComponent], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts index dcc5e6f804c..e1839d520f0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts @@ -4,7 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { PopoverModule } from 'ngx-bootstrap/popover'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { ExecutingTask } from '../../../shared/models/executing-task'; import { FinishedTask } from '../../../shared/models/finished-task'; import { SharedModule } from '../../../shared/shared.module'; @@ -20,7 +20,8 @@ describe('TaskManagerComponent', () => { configureTestBed({ imports: [SharedModule, PopoverModule.forRoot(), HttpClientTestingModule, RouterTestingModule], - declarations: [TaskManagerComponent] + declarations: [TaskManagerComponent], + providers: [i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts index 1b000f238e8..8bdca309858 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts @@ -4,7 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { AlertModule } from 'ngx-bootstrap/alert'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { SettingsService } from '../../../shared/api/settings.service'; import { SummaryService } from '../../../shared/services/summary.service'; import { CephReleaseNamePipe } from '../../pipes/ceph-release-name.pipe'; @@ -19,7 +19,7 @@ describe('GrafanaComponent', () => { configureTestBed({ declarations: [GrafanaComponent, InfoPanelComponent, LoadingPanelComponent], imports: [AlertModule.forRoot(), HttpClientTestingModule, RouterTestingModule], - providers: [CephReleaseNamePipe, SettingsService, SummaryService] + providers: [CephReleaseNamePipe, SettingsService, SummaryService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.spec.ts index 5df82fae27d..6a28aecb13f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AlertModule } from 'ngx-bootstrap/alert'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; import { InfoPanelComponent } from './info-panel.component'; describe('InfoPanelComponent', () => { @@ -11,7 +11,8 @@ describe('InfoPanelComponent', () => { configureTestBed({ declarations: [InfoPanelComponent], - imports: [AlertModule.forRoot()] + imports: [AlertModule.forRoot()], + providers: i18nProviders }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.ts index f6c5d1fdbfa..ce0ef7ffe27 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/info-panel/info-panel.component.ts @@ -1,5 +1,7 @@ import { Component, Input } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + @Component({ selector: 'cd-info-panel', templateUrl: './info-panel.component.html', @@ -11,5 +13,7 @@ export class InfoPanelComponent { * @type {string} */ @Input() - title = 'Information'; + title = this.i18n('Information'); + + constructor(private i18n: I18n) {} } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/api-interceptor.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/api-interceptor.service.spec.ts index 7c01b8a3033..7d569ad6f7d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/api-interceptor.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/api-interceptor.service.spec.ts @@ -3,7 +3,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; -import { configureTestBed } from '../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { AppModule } from '../../app.module'; import { ApiInterceptorService } from './api-interceptor.service'; import { NotificationService } from './notification.service'; @@ -45,7 +45,7 @@ describe('ApiInterceptorService', () => { configureTestBed({ imports: [AppModule, HttpClientTestingModule], - providers: [NotificationService] + providers: [NotificationService, i18nProviders] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.spec.ts index 56a2bad89f6..f751d761794 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/notification.service.spec.ts @@ -3,7 +3,7 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import * as _ from 'lodash'; import { ToastsManager } from 'ng2-toastr'; -import { configureTestBed } from '../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { NotificationType } from '../enum/notification-type.enum'; import { FinishedTask } from '../models/finished-task'; import { NotificationService } from './notification.service'; @@ -21,7 +21,8 @@ describe('NotificationService', () => { providers: [ NotificationService, TaskMessageService, - { provide: ToastsManager, useValue: toastFakeService } + { provide: ToastsManager, useValue: toastFakeService }, + i18nProviders ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-list.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-list.service.spec.ts index 0761d044aab..0c6465994c0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-list.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-list.service.spec.ts @@ -4,7 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { ExecutingTask } from '../models/executing-task'; import { SummaryService } from './summary.service'; import { TaskListService } from './task-list.service'; @@ -24,7 +24,7 @@ describe('TaskListService', () => { }; configureTestBed({ - providers: [TaskListService, TaskMessageService, SummaryService], + providers: [TaskListService, TaskMessageService, SummaryService, i18nProviders], imports: [HttpClientTestingModule, RouterTestingModule] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.spec.ts index 37956f16ac3..b97d065ab36 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.spec.ts @@ -1,5 +1,8 @@ +import { TestBed } from '@angular/core/testing'; + import * as _ from 'lodash'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { FinishedTask } from '../models/finished-task'; import { TaskException } from '../models/task-exception'; import { TaskMessageOperation, TaskMessageService } from './task-message.service'; @@ -8,8 +11,12 @@ describe('TaskManagerMessageService', () => { let service: TaskMessageService; let finishedTask: FinishedTask; + configureTestBed({ + providers: [TaskMessageService, i18nProviders] + }); + beforeEach(() => { - service = new TaskMessageService(); + service = TestBed.get(TaskMessageService); finishedTask = new FinishedTask(); }); @@ -210,8 +217,8 @@ describe('TaskManagerMessageService', () => { finishedTask.name = 'rbd/trash/restore'; testMessages( new TaskMessageOperation('Restoring', 'restore', 'Restored'), - `image '${metadata.pool_name}@${metadata.image_id}' \ - into '${metadata.pool_name}/${metadata.new_image_name}'` + `image '${metadata.pool_name}@${metadata.image_id}' ` + + `into '${metadata.pool_name}/${metadata.new_image_name}'` ); testErrorCode( 17, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.ts index 51db2e7a82e..d268744b3bb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-message.service.ts @@ -1,5 +1,7 @@ import { Injectable } from '@angular/core'; +import { I18n } from '@ngx-translate/i18n-polyfill'; + import { Components } from '../enum/components.enum'; import { FinishedTask } from '../models/finished-task'; import { Task } from '../models/task'; @@ -23,6 +25,7 @@ class TaskMessage { errors: (metadata) => object; failure(metadata): string { + // TODO: I18N return `Failed to ${this.operation.failure} ${this.involves(metadata)}`; } @@ -49,12 +52,15 @@ class TaskMessage { providedIn: ServicesModule }) export class TaskMessageService { - constructor() {} + constructor(private i18n: I18n) {} defaultMessage = new TaskMessage( - new TaskMessageOperation('Executing', 'execute', 'Executed'), + new TaskMessageOperation(this.i18n('Executing'), this.i18n('execute'), this.i18n('Executed')), (metadata) => { - return (metadata && (Components[metadata.component] || metadata.component)) || 'unknown task'; + return ( + (metadata && (Components[metadata.component] || metadata.component)) || + this.i18n('unknown task') + ); }, () => { return {}; @@ -62,60 +68,117 @@ export class TaskMessageService { ); commonOperations = { - create: new TaskMessageOperation('Creating', 'create', 'Created'), - update: new TaskMessageOperation('Updating', 'update', 'Updated'), - delete: new TaskMessageOperation('Deleting', 'delete', 'Deleted') + create: new TaskMessageOperation( + this.i18n('Creating'), + this.i18n('create'), + this.i18n('Created') + ), + update: new TaskMessageOperation( + this.i18n('Updating'), + this.i18n('update'), + this.i18n('Updated') + ), + delete: new TaskMessageOperation( + this.i18n('Deleting'), + this.i18n('delete'), + this.i18n('Deleted') + ) }; rbd = { - default: (metadata) => `RBD '${metadata.pool_name}/${metadata.image_name}'`, - child: (metadata) => `RBD '${metadata.child_pool_name}/${metadata.child_image_name}'`, - destination: (metadata) => `RBD '${metadata.dest_pool_name}/${metadata.dest_image_name}'`, + default: (metadata) => + this.i18n(`RBD '{{id}}'`, { + id: `${metadata.pool_name}/${metadata.image_name}` + }), + child: (metadata) => + this.i18n(`RBD '{{id}}'`, { + id: `${metadata.child_pool_name}/${metadata.child_image_name}` + }), + destination: (metadata) => + this.i18n(`RBD '{{id}}'`, { + id: `${metadata.dest_pool_name}/${metadata.dest_image_name}` + }), snapshot: (metadata) => - `RBD snapshot '${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'` + this.i18n(`RBD snapshot '{{id}}'`, { + id: `${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}` + }) }; messages = { // Pool tasks - 'pool/create': new TaskMessage(this.commonOperations.create, this.pool, (metadata) => ({ - '17': `Name is already used by ${this.pool(metadata)}.` - })), - 'pool/edit': new TaskMessage(this.commonOperations.update, this.pool, (metadata) => ({ - '17': `Name is already used by ${this.pool(metadata)}.` - })), - 'pool/delete': new TaskMessage(this.commonOperations.delete, this.pool), + 'pool/create': new TaskMessage( + this.commonOperations.create, + (metadata) => this.pool(metadata), + (metadata) => ({ + '17': this.i18n('Name is already used by {{pool_name}}.', { + pool_name: this.pool(metadata) + }) + }) + ), + 'pool/edit': new TaskMessage( + this.commonOperations.update, + (metadata) => this.pool(metadata), + (metadata) => ({ + '17': this.i18n('Name is already used by {{pool_name}}.', { + pool_name: this.pool(metadata) + }) + }) + ), + 'pool/delete': new TaskMessage(this.commonOperations.delete, (metadata) => this.pool(metadata)), // Erasure code profile tasks - 'ecp/create': new TaskMessage(this.commonOperations.create, this.ecp, (metadata) => ({ - '17': `Name is already used by ${this.ecp(metadata)}.` - })), - 'ecp/delete': new TaskMessage(this.commonOperations.delete, this.ecp), + 'ecp/create': new TaskMessage( + this.commonOperations.create, + (metadata) => this.ecp(metadata), + (metadata) => ({ + '17': this.i18n('Name is already used by {{name}}.', { + name: this.ecp(metadata) + }) + }) + ), + 'ecp/delete': new TaskMessage(this.commonOperations.delete, (metadata) => this.ecp(metadata)), // RBD tasks 'rbd/create': new TaskMessage(this.commonOperations.create, this.rbd.default, (metadata) => ({ - '17': `Name is already used by ${this.rbd.default(metadata)}.` + '17': this.i18n('Name is already used by {{rbd_name}}.', { + rbd_name: this.rbd.default(metadata) + }) })), 'rbd/edit': new TaskMessage(this.commonOperations.update, this.rbd.default, (metadata) => ({ - '17': `Name is already used by ${this.rbd.default(metadata)}.` + '17': this.i18n('Name is already used by {{rbd_name}}.', { + rbd_name: this.rbd.default(metadata) + }) })), 'rbd/delete': new TaskMessage(this.commonOperations.delete, this.rbd.default, (metadata) => ({ - '39': `${this.rbd.default(metadata)} contains snapshots.` + '39': this.i18n('{{rbd_name}} contains snapshots.', { + rbd_name: this.rbd.default(metadata) + }) })), 'rbd/clone': new TaskMessage( - new TaskMessageOperation('Cloning', 'clone', 'Cloned'), + new TaskMessageOperation(this.i18n('Cloning'), this.i18n('clone'), this.i18n('Cloned')), this.rbd.child, (metadata) => ({ - '17': `Name is already used by ${this.rbd.child(metadata)}.`, - '22': `Snapshot of ${this.rbd.child(metadata)} must be protected.` + '17': this.i18n('Name is already used by {{rbd_name}}.', { + rbd_name: this.rbd.child(metadata) + }), + '22': this.i18n('Snapshot of {{rbd_name}} must be protected.', { + rbd_name: this.rbd.child(metadata) + }) }) ), 'rbd/copy': new TaskMessage( - new TaskMessageOperation('Copying', 'copy', 'Copied'), + new TaskMessageOperation(this.i18n('Copying'), this.i18n('copy'), this.i18n('Copied')), this.rbd.destination, (metadata) => ({ - '17': `Name is already used by ${this.rbd.destination(metadata)}.` + '17': this.i18n('Name is already used by {{rbd_name}}.', { + rbd_name: this.rbd.destination(metadata) + }) }) ), 'rbd/flatten': new TaskMessage( - new TaskMessageOperation('Flattening', 'flatten', 'Flattened'), + new TaskMessageOperation( + this.i18n('Flattening'), + this.i18n('flatten'), + this.i18n('Flattened') + ), this.rbd.default ), // RBD snapshot tasks @@ -123,66 +186,90 @@ export class TaskMessageService { this.commonOperations.create, this.rbd.snapshot, (metadata) => ({ - '17': `Name is already used by ${this.rbd.snapshot(metadata)}.` + '17': this.i18n('Name is already used by {{snap_name}}.', { + snap_name: this.rbd.snapshot(metadata) + }) }) ), 'rbd/snap/edit': new TaskMessage( this.commonOperations.update, this.rbd.snapshot, (metadata) => ({ - '16': `Cannot unprotect ${this.rbd.snapshot(metadata)} because it contains child images.` + '16': this.i18n('Cannot unprotect {{snap_name}} because it contains child images.', { + snap_name: this.rbd.snapshot(metadata) + }) }) ), 'rbd/snap/delete': new TaskMessage( this.commonOperations.delete, this.rbd.snapshot, (metadata) => ({ - '16': `Cannot delete ${this.rbd.snapshot(metadata)} because it's protected.` + '16': this.i18n(`Cannot delete {{snap_name}} because it's protected.`, { + snap_name: this.rbd.snapshot(metadata) + }) }) ), 'rbd/snap/rollback': new TaskMessage( - new TaskMessageOperation('Rolling back', 'rollback', 'Rolled back'), + new TaskMessageOperation( + this.i18n('Rolling back'), + this.i18n('rollback'), + this.i18n('Rolled back') + ), this.rbd.snapshot ), // RBD trash tasks 'rbd/trash/move': new TaskMessage( - new TaskMessageOperation('Moving', 'move', 'Moved'), - (metadata) => `image '${metadata.pool_name}/${metadata.image_name}' to trash`, + new TaskMessageOperation(this.i18n('Moving'), this.i18n('move'), this.i18n('Moved')), + (metadata) => + this.i18n(`image '{{id}}' to trash`, { + id: `${metadata.pool_name}/${metadata.image_name}` + }), () => ({ - 2: `Could not find image.` + 2: this.i18n('Could not find image.') }) ), 'rbd/trash/restore': new TaskMessage( - new TaskMessageOperation('Restoring', 'restore', 'Restored'), + new TaskMessageOperation(this.i18n('Restoring'), this.i18n('restore'), this.i18n('Restored')), (metadata) => - `image '${metadata.pool_name}@${metadata.image_id}' \ - into '${metadata.pool_name}/${metadata.new_image_name}'`, + this.i18n(`image '{{id}}' into '{{new_id}}'`, { + id: `${metadata.pool_name}@${metadata.image_id}`, + new_id: `${metadata.pool_name}/${metadata.new_image_name}` + }), (metadata) => ({ - 17: `Image name '${metadata.pool_name}/${metadata.new_image_name}' is already in use.` + 17: this.i18n(`Image name '{{id}}' is already in use.`, { + id: `${metadata.pool_name}/${metadata.new_image_name}` + }) }) ), 'rbd/trash/remove': new TaskMessage( - new TaskMessageOperation('Deleting', 'delete', 'Deleted'), - (metadata) => `image '${metadata.pool_name}/${metadata.image_name}@${metadata.image_id}'` + new TaskMessageOperation(this.i18n('Deleting'), this.i18n('delete'), this.i18n('Deleted')), + (metadata) => + this.i18n(`image '{{id}}'`, { + id: `${metadata.pool_name}/${metadata.image_name}@${metadata.image_id}` + }) ), 'rbd/trash/purge': new TaskMessage( - new TaskMessageOperation('Purging', 'purge', 'Purged'), + new TaskMessageOperation(this.i18n('Purging'), this.i18n('purge'), this.i18n('Purged')), (metadata) => { - let message = 'all pools'; + let message = this.i18n('all pools'); if (metadata.pool_name) { message = `'${metadata.pool_name}'`; } - return `images from ${message}`; + return this.i18n('images from {{message}}', { + message: message + }); } ) }; pool(metadata) { - return `pool '${metadata.pool_name}'`; + return this.i18n(`pool '{{pool_name}}'`, { + pool_name: metadata.pool_name + }); } ecp(metadata) { - return `erasure code profile '${metadata.name}'`; + return this.i18n(`erasure code profile '{{name}}'`, { name: metadata.name }); } _getTaskTitle(task: Task) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.spec.ts index be510a51e60..75968de6904 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.spec.ts @@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { Observable } from 'rxjs'; -import { configureTestBed } from '../../../testing/unit-test-helper'; +import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; import { FinishedTask } from '../models/finished-task'; import { SharedModule } from '../shared.module'; import { NotificationService } from './notification.service'; @@ -18,7 +18,7 @@ describe('TaskWrapperService', () => { configureTestBed({ imports: [HttpClientTestingModule, ToastModule.forRoot(), SharedModule, RouterTestingModule], - providers: [TaskWrapperService] + providers: [TaskWrapperService, i18nProviders] }); beforeEach(inject([TaskWrapperService], (wrapper: TaskWrapperService) => { diff --git a/src/pybind/mgr/dashboard/frontend/src/testing/unit-test-helper.ts b/src/pybind/mgr/dashboard/frontend/src/testing/unit-test-helper.ts index bd396d34462..b294aab4e65 100644 --- a/src/pybind/mgr/dashboard/frontend/src/testing/unit-test-helper.ts +++ b/src/pybind/mgr/dashboard/frontend/src/testing/unit-test-helper.ts @@ -1,7 +1,9 @@ +import { LOCALE_ID, TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { AbstractControl } from '@angular/forms'; import { By } from '@angular/platform-browser'; +import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; import { TableActionsComponent } from '../app/shared/datatable/table-actions/table-actions.component'; @@ -179,3 +181,21 @@ export class FormHelper { expect(Boolean(fixture.debugElement.query(By.css(css)))).toBe(visibility); } } + +const XLIFF = ` + + + + + + +`; + +const i18nProviders = [ + { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, + { provide: TRANSLATIONS, useValue: XLIFF }, + { provide: LOCALE_ID, useValue: 'en' }, + I18n +]; + +export { i18nProviders }; -- 2.39.5