diff --git a/console/src/app/app.component.ts b/console/src/app/app.component.ts index 62b0f8e60c..c73ae17693 100644 --- a/console/src/app/app.component.ts +++ b/console/src/app/app.component.ts @@ -220,7 +220,9 @@ export class AppComponent implements OnDestroy { this.authService.user.subscribe(userprofile => { this.profile = userprofile; - const lang = userprofile.preferredLanguage.match(/en|de/) ? userprofile.preferredLanguage : 'en'; + const cropped = navigator.language.split('-')[0] ?? 'en'; + const fallbackLang = cropped.match(/en|de/) ? cropped : 'en'; + const lang = userprofile.preferredLanguage.match(/en|de/) ? userprofile.preferredLanguage : fallbackLang; this.translate.use(lang); this.document.documentElement.lang = lang; }); diff --git a/console/src/app/app.module.ts b/console/src/app/app.module.ts index b72fe30318..5a783d3833 100644 --- a/console/src/app/app.module.ts +++ b/console/src/app/app.module.ts @@ -40,6 +40,7 @@ import { GrpcAuthService } from './services/grpc-auth.service'; import { GrpcService } from './services/grpc.service'; import { AuthInterceptor } from './services/interceptors/auth.interceptor'; import { GRPC_INTERCEPTORS } from './services/interceptors/grpc-interceptor'; +import { I18nInterceptor } from './services/interceptors/i18n.interceptor'; import { OrgInterceptor } from './services/interceptors/org.interceptor'; import { RefreshService } from './services/refresh.service'; import { StatehandlerProcessorService, StatehandlerProcessorServiceImpl } from './services/statehandler-processor.service'; @@ -156,6 +157,11 @@ const authConfig: AuthConfig = { multi: true, useClass: AuthInterceptor, }, + { + provide: GRPC_INTERCEPTORS, + multi: true, + useClass: I18nInterceptor, + }, { provide: GRPC_INTERCEPTORS, multi: true, diff --git a/console/src/app/modules/add-member-dialog/member-create-dialog.module.ts b/console/src/app/modules/add-member-dialog/member-create-dialog.module.ts index 9c2671c6b4..b7909253e8 100644 --- a/console/src/app/modules/add-member-dialog/member-create-dialog.module.ts +++ b/console/src/app/modules/add-member-dialog/member-create-dialog.module.ts @@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; +import { MatChipsModule } from '@angular/material/chips'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { TranslateModule } from '@ngx-translate/core'; import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module'; @@ -21,6 +23,8 @@ import { MemberCreateDialogComponent } from './member-create-dialog.component'; CommonModule, MatDialogModule, MatButtonModule, + MatChipsModule, + MatInputModule, TranslateModule, MatFormFieldModule, MatSelectModule, diff --git a/console/src/app/modules/idp-table/idp-table.component.html b/console/src/app/modules/idp-table/idp-table.component.html index 0e1ec3ebf9..f1750e8fec 100644 --- a/console/src/app/modules/idp-table/idp-table.component.html +++ b/console/src/app/modules/idp-table/idp-table.component.html @@ -4,12 +4,12 @@ diff --git a/console/src/app/pages/users/user-list/user-table/user-table.component.scss b/console/src/app/pages/users/user-list/user-table/user-table.component.scss index 4c3167ba1b..df6717dcd4 100644 --- a/console/src/app/pages/users/user-list/user-table/user-table.component.scss +++ b/console/src/app/pages/users/user-list/user-table/user-table.component.scss @@ -8,6 +8,7 @@ td, th { padding: .5rem; + outline: none; &:first-child { padding-left: 0; @@ -27,8 +28,6 @@ } tr { - outline: none; - button { visibility: hidden; } diff --git a/console/src/app/pages/users/user-list/user-table/user-table.component.ts b/console/src/app/pages/users/user-list/user-table/user-table.component.ts index 9c94ca12c7..5c5a611e34 100644 --- a/console/src/app/pages/users/user-list/user-table/user-table.component.ts +++ b/console/src/app/pages/users/user-list/user-table/user-table.component.ts @@ -152,7 +152,6 @@ export class UserTableComponent implements OnInit { confirmKey: 'ACTIONS.DELETE', cancelKey: 'ACTIONS.CANCEL', titleKey: 'USER.DIALOG.DELETE_TITLE', - descriptionParam: user.human ?? user.machine ? { displayName: user.machine?.name } : { displayName: '' }, descriptionKey: 'USER.DIALOG.DELETE_DESCRIPTION', }, width: '400px', diff --git a/console/src/app/services/grpc.service.ts b/console/src/app/services/grpc.service.ts index 3a829385db..055c583b23 100644 --- a/console/src/app/services/grpc.service.ts +++ b/console/src/app/services/grpc.service.ts @@ -9,6 +9,7 @@ import { AuthServicePromiseClient } from '../proto/generated/auth_grpc_web_pb'; import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb'; import { AuthenticationService } from './authentication.service'; import { AuthInterceptor } from './interceptors/auth.interceptor'; +import { I18nInterceptor } from './interceptors/i18n.interceptor'; import { OrgInterceptor } from './interceptors/org.interceptor'; import { StorageService } from './storage.service'; @@ -37,6 +38,7 @@ export class GrpcService { unaryInterceptors: [ new OrgInterceptor(this.storageService), new AuthInterceptor(this.authenticationService, this.storageService, this.dialog), + new I18nInterceptor(), ], }; diff --git a/console/src/app/services/interceptors/i18n.interceptor.ts b/console/src/app/services/interceptors/i18n.interceptor.ts new file mode 100644 index 0000000000..024e2e52d2 --- /dev/null +++ b/console/src/app/services/interceptors/i18n.interceptor.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { Request, UnaryInterceptor, UnaryResponse } from 'grpc-web'; + + +const i18nHeader = 'Accept-Language'; +@Injectable({ providedIn: 'root' }) +/** + * Set the navigator language as header to all grpc requests + */ +export class I18nInterceptor implements UnaryInterceptor { + constructor() { } + + public async intercept(request: Request, invoker: any): Promise> { + const metadata = request.getMetadata(); + + const navLang = navigator.language; + if (navLang) { + metadata[i18nHeader] = navLang; + } + + return invoker(request).then((response: any) => { + return response; + }).catch((error: any) => { + return Promise.reject(error); + }); + } +} diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index c013422808..ec929495c2 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -94,7 +94,7 @@ }, "DIALOG": { "DELETE_TITLE":"User löschen", - "DELETE_DESCRIPTION":"Sie sind im Begriff den Benutzer {{displayName}} entgültig zu löschen. Wollen Sie dies wirklich tun?" + "DELETE_DESCRIPTION":"Sie sind im Begriff einen Benutzer endgültig zu löschen. Wollen Sie dies wirklich tun?" }, "TABLE":{ "DEACTIVATE":"Deaktivieren", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index c8b865c357..3f9eef018c 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -94,7 +94,7 @@ }, "DIALOG": { "DELETE_TITLE":"Delete User", - "DELETE_DESCRIPTION":"You are about to permanently delete the user {{displayName}}. Are you sure?" + "DELETE_DESCRIPTION":"You are about to permanently delete a user. Are you sure?" }, "TABLE":{ "DEACTIVATE":"Deactivate",