diff --git a/ui/angular.json b/ui/angular.json index a07983c60..ac6655061 100644 --- a/ui/angular.json +++ b/ui/angular.json @@ -4,6 +4,21 @@ "newProjectRoot": "projects", "projects": { "ui": { + "i18n": { + "sourceLocale": "en", + "locales": { + "cs": "src/i18n/messages.cs.xlf", + "es": "src/i18n/messages.es.xlf", + "fr": "src/i18n/messages.fr.xlf", + "it": "src/i18n/messages.it.xlf", + "ja": "src/i18n/messages.ja.xlf", + "ko": "src/i18n/messages.ko.xlf", + "pt": "src/i18n/messages.pt.xlf", + "ru": "src/i18n/messages.ru.xlf", + "zh-CN": "src/i18n/messages.zh-CN.xlf", + "zh-TW": "src/i18n/messages.zh-TW.xlf" + } + }, "projectType": "application", "schematics": { "@schematics/angular:component": { @@ -17,6 +32,18 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "localize": [ + "fr", + "es", + "cs", + "it", + "ja", + "ko", + "pt", + "ru", + "zh-CN", + "zh-TW" + ], "outputPath": "dist/", "index": "src/index.html", "main": "src/main.ts", @@ -50,6 +77,7 @@ "outputHashing": "all" }, "development": { + "localize": ["en"], "buildOptimizer": false, "optimization": false, "vendorChunk": true, @@ -77,9 +105,24 @@ "defaultConfiguration": "development" }, "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", + "builder": "ng-extract-i18n-merge:ng-extract-i18n-merge", "options": { - "browserTarget": "ui:build" + "includeContext": true, + "browserTarget": "ui:build", + "format": "xlf", + "outputPath": "src/i18n", + "targetFiles": [ + "messages.cs.xlf", + "messages.es.xlf", + "messages.fr.xlf", + "messages.it.xlf", + "messages.ja.xlf", + "messages.ko.xlf", + "messages.pt.xlf", + "messages.ru.xlf", + "messages.zh-CN.xlf", + "messages.zh-TW.xlf" + ] } }, "test": { diff --git a/ui/src/app/account/login/login.component.html b/ui/src/app/account/login/login.component.html index 70dcfb5d4..c7b6e1b73 100644 --- a/ui/src/app/account/login/login.component.html +++ b/ui/src/app/account/login/login.component.html @@ -2,49 +2,45 @@
-
+
Failed to sign in! Please check your credentials and try again.
- - +
- - +
-
+
Please enter the MFA code from your authenticator app
-
+
Invalid MFA code
- +
- @@ -55,7 +51,7 @@ class="alert-link" (click)="requestResetPassword()" (keypress)="requestResetPassword()" - jhiTranslate="login.password.forgot.string" + i18n="@@login.password.forgot.string" >Did you forget your password?
diff --git a/ui/src/app/account/login/login.component.ts b/ui/src/app/account/login/login.component.ts index 83bbc9c86..32e30f75f 100644 --- a/ui/src/app/account/login/login.component.ts +++ b/ui/src/app/account/login/login.component.ts @@ -86,8 +86,6 @@ export class LoginComponent implements AfterViewInit, OnDestroy { take(1) ) .subscribe((account) => { - // TODO: remove after sprint review - console.log('Login successful, account data:', account) this.loginSuccess() }) } else { diff --git a/ui/src/app/account/password/password-reset-init.component.html b/ui/src/app/account/password/password-reset-init.component.html index c21462f25..9d684b6f4 100644 --- a/ui/src/app/account/password/password-reset-init.component.html +++ b/ui/src/app/account/password/password-reset-init.component.html @@ -1,46 +1,81 @@
-
-
-

Reset your password

+
+
+

Reset your password

-
- Email address isn't registered! Please check and try again. -
+
+ Email address isn't registered! Please check and try again. +
-
-

Enter the email address you used to register.

-
+
+

Enter the email address you used to register.

+
-
-

Check your emails for details on how to reset your password.

-
+
+

+ Check your emails for details on how to reset your password. +

+
-
-
- - -
- - Your email is required. - - - Your email is invalid. - - - Your email is required to be at least 5 characters. - - - Your email cannot be longer than 100 characters. - -
-
- -
+
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+ +
+
diff --git a/ui/src/app/account/service/account.service.ts b/ui/src/app/account/service/account.service.ts index 9d49fb025..5c42c1395 100644 --- a/ui/src/app/account/service/account.service.ts +++ b/ui/src/app/account/service/account.service.ts @@ -71,8 +71,9 @@ export class AccountService { return this.http.get('/services/userservice/api/account/mfa') } - save(account: any): Observable> { - return this.http.post('/services/userservice/api/account', account, { observe: 'response' }) + save(account: IAccount): Observable> { + const headers = { 'Accept-Language': account.langKey } + return this.http.post('/services/userservice/api/account', account, { observe: 'response', headers }) } enableMfa(mfaSetup: any): Observable> { diff --git a/ui/src/app/account/settings/settings.component.html b/ui/src/app/account/settings/settings.component.html index de18a8683..ec3ce29c6 100644 --- a/ui/src/app/account/settings/settings.component.html +++ b/ui/src/app/account/settings/settings.component.html @@ -1,138 +1,248 @@
-
-
-

Personal details

-
+
+
+

Personal details

+
-
- Settings saved! -
- -
-
- - - -
- - Your first name is required. - - - Your first name is required to be at least 1 character. - - - Your first name cannot be longer than 50 characters. - -
-
-
- - - - -
- - Your last name is required. - - - Your last name is required to be at least 1 character. - - - Your last name cannot be longer than 50 characters. - -
-
-
- - - +
+ Settings saved! +
-
-
- - -
- -
-
- -
-

Security

-
-
-

Add extra security to your ORCID member portal account by enabling two-factor authentication. Each time you sign in, you'll be prompted to enter a six-digit code we send to your preferred authentication application.

- - -
-
2FA settings updated
-
-
-
    -
  • Install a two-factor authentication app
    A 2FA app is required to create the six-digit code you need to access your account each time you sign in. Most apps are for mobile devices; some are also available as desktop or web-based apps. Download and install your preferred 2FA app, such as Google Authenticator, FreeOTP, or Authy.
  • -
  • Scan this QR code with your device
    Open your 2FA app and scan the image below.
  • -
-
-
-
-
- QR Code -
-
-
-
-

{{ mfaSetup.secret }}

-
-
-
-
-
    -
  • Can't scan the QR code?
    Get a text code and enter it into your 2FA app instead
  • -
  • Enter the six-digit code from the app
    After scanning the QR code or entering in the text code, your 2FA app will display a six-digit code. Enter this code in the box below and click Save.
  • -
-
-
-
-
-
- Incorrect verification code -
- + +
+ + +
+ + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + +
+
+
+ + +
+
+ + +
+ + +
- -
-
-
-
-

Make a note of the following backup codes, this is the only time they will be shown.

- - - - -
{{ backupCode }}
-
-
- - -
-
+
+

Security

+
+
+

+ Add extra security to your ORCID member portal account by enabling two-factor authentication. Each time you + sign in, you'll be prompted to enter a six-digit code we send to your preferred authentication application. +

+ + +
+
2FA settings updated
+
+
+
    +
  • + Install a two-factor authentication app
    A 2FA app is required to create the six-digit code you need + to access your account each time you sign in. Most apps are for mobile devices; some are also available + as desktop or web-based apps. Download and install your preferred 2FA app, such as + Google Authenticator, FreeOTP, or Authy. +
  • +
  • + Scan this QR code with your device
    Open your 2FA app and scan the image below. +
  • +
+
+
+
+
+ QR Code +
+
+
+
+

+ {{ mfaSetup.secret }} +

+
+
+
+
+
    +
  • + Can't scan the QR code?
    Get a text code and enter it into your 2FA app instead +
  • +
  • + Enter the six-digit code from the app
    After scanning the QR code or entering in the text code, your + 2FA app will display a six-digit code. Enter this code in the box below and click Save. +
  • +
+
+
+
+
+
+ Incorrect verification code +
+ +
+
+
+
+

+ Make a note of the following backup codes, this is the only time they will be shown. +

+ + + + +
{{ backupCode }}
+
+
+ +
+
- +
diff --git a/ui/src/app/account/settings/settings.component.spec.ts b/ui/src/app/account/settings/settings.component.spec.ts index 3e04d7e35..96d2a33aa 100644 --- a/ui/src/app/account/settings/settings.component.spec.ts +++ b/ui/src/app/account/settings/settings.component.spec.ts @@ -6,6 +6,7 @@ import { HttpClientModule, HttpResponse } from '@angular/common/http' import { LanguageService } from 'src/app/shared/service/language.service' import { AccountService } from '../service/account.service' import { of, throwError } from 'rxjs' +import { FindLanguageFromKeyPipe } from 'src/app/shared/pipe/find-language-from-key' describe('SettingsComponent', () => { let component: SettingsComponent @@ -29,7 +30,7 @@ describe('SettingsComponent', () => { ]) TestBed.configureTestingModule({ - declarations: [SettingsComponent], + declarations: [SettingsComponent, FindLanguageFromKeyPipe], imports: [ReactiveFormsModule, HttpClientModule], providers: [ { provide: LanguageService, useValue: languageServiceSpy }, @@ -40,6 +41,21 @@ describe('SettingsComponent', () => { fixture = TestBed.createComponent(SettingsComponent) component = fixture.componentInstance accountServiceSpy = TestBed.inject(AccountService) as jasmine.SpyObj + + languageServiceSpy.getAllLanguages.and.returnValue({ + en: { name: 'English' }, + es: { name: 'Español' }, + fr: { name: 'Français' }, + ja: { name: '日本語' }, + 'zh-TW': { name: '繁體中文' }, + 'zh-CN': { name: '简体中文' }, + cs: { name: 'Čeština' }, + it: { name: 'Italiano' }, + ko: { name: '한국어' }, + pt: { name: 'Português' }, + ru: { name: 'Pусский' }, + xx: { name: 'Test' }, + }) }) it('should create', () => { diff --git a/ui/src/app/account/settings/settings.component.ts b/ui/src/app/account/settings/settings.component.ts index bbab08e42..7ab001ff6 100644 --- a/ui/src/app/account/settings/settings.component.ts +++ b/ui/src/app/account/settings/settings.component.ts @@ -11,6 +11,7 @@ import { IAccount } from '../model/account.model' styleUrls: ['./settings.component.scss'], }) export class SettingsComponent implements OnInit { + account: IAccount | undefined error: string | undefined success: string | undefined languages: any[] | undefined @@ -48,30 +49,25 @@ export class SettingsComponent implements OnInit { this.showMfaSetup = false this.showMfaTextCode = false this.showMfaBackupCodes = false - console.log('calling get account data') this.accountService.getAccountData().subscribe((account) => { - console.log('got account data', account) if (account) { + this.account = account this.updateForm(account) this.updateMfaForm(account) this.userName = this.accountService.getUserName() - console.log('acocunt and account mfa enabled are ', account, ' and ', account.mfaEnabled) if (account && !account.mfaEnabled) { this.accountService.getMfaSetup().subscribe((res) => { - console.log('setting mfa setup to ' + res) this.mfaSetup = res }) } } }) - this.languages = this.languageService.getAllLanguages() + this.languages = Object.keys(this.languageService.getAllLanguages()) } mfaEnabledStateChange(): void { - console.log('mfa state change called') this.showMfaUpdated = false const mfaEnabled = this.mfaForm.get('mfaEnabled')!.value - console.log('setup is ' + this.mfaSetup) if (mfaEnabled && this.mfaSetup) { this.showMfaSetup = true this.showMfaBackupCodes = false @@ -91,17 +87,15 @@ export class SettingsComponent implements OnInit { next: () => { this.error = undefined this.success = 'OK' - this.accountService.getAccountData().subscribe((account) => { + this.accountService.getAccountData(true).subscribe((account) => { if (account) { + if (settingsAccount.langKey !== account.langKey) { + location.reload() + } this.updateForm(account) this.updateMfaForm(account) } }) - this.languageService.getCurrentLanguage().subscribe((current) => { - if (settingsAccount.langKey !== current) { - this.languageService.changeLanguage(settingsAccount.langKey) - } - }) }, error: () => { this.success = undefined diff --git a/ui/src/app/layout/footer/footer.component.html b/ui/src/app/layout/footer/footer.component.html index 1b44b11d2..cf470dd37 100644 --- a/ui/src/app/layout/footer/footer.component.html +++ b/ui/src/app/layout/footer/footer.component.html @@ -1,20 +1,28 @@ diff --git a/ui/src/app/layout/navbar/navbar.component.html b/ui/src/app/layout/navbar/navbar.component.html index f41071d7a..b59da53f7 100644 --- a/ui/src/app/layout/navbar/navbar.component.html +++ b/ui/src/app/layout/navbar/navbar.component.html @@ -1,7 +1,7 @@
- - {{ this.getUserName() }} | + {{ this.getUserName() }} | {{ this.getUserName() }} @@ -12,7 +12,7 @@ > -   +