From f66cbee82f0c4b42cd8326acbe46aee4569b0358 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Tue, 4 Sep 2018 09:41:18 -0700 Subject: [PATCH 01/23] [NOJIRA] Added swagger-ui to the backend build. For devs: access via http://localhost:8080/swagger-ui.html --- backend/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/build.gradle b/backend/build.gradle index 2ffd807f7..e6cf12818 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -99,6 +99,7 @@ dependencies { //Swagger compile 'io.springfox:springfox-swagger2:2.9.2' + compile 'io.springfox:springfox-swagger-ui:2.9.2' testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.spockframework:spock-core:1.1-groovy-2.4" @@ -206,4 +207,4 @@ jacocoTestReport { csv.enabled = false html.destination = file("${buildDir}/jacocoHtml") } -} \ No newline at end of file +} From 95256b69b23f3e8aefcff8c8079751a02a120dc6 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Wed, 5 Sep 2018 12:33:49 -0700 Subject: [PATCH 02/23] SHIBUI-814 Integrated with rest endpoint for messages --- .../resources/i18n/messages_en-US.properties | 11 ++++ .../resources/i18n/messages_en.properties | 12 +++- ui/src/app/app.component.ts | 9 ++- ui/src/app/app.module.ts | 4 +- ui/src/app/core/action/message.action.ts | 39 ++++++++++++ ui/src/app/core/core.module.ts | 7 ++- ui/src/app/core/effect/message.effect.ts | 45 ++++++++++++++ ui/src/app/core/effect/user.effect.ts | 4 +- ui/src/app/core/reducer/index.ts | 11 +++- ui/src/app/core/reducer/message.reducer.ts | 60 +++++++++++++++++++ ui/src/app/core/service/i18n.service.ts | 31 ++++++++++ ui/src/app/shared/util.ts | 42 +++++++++++++ 12 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 backend/src/main/resources/i18n/messages_en-US.properties create mode 100644 ui/src/app/core/action/message.action.ts create mode 100644 ui/src/app/core/effect/message.effect.ts create mode 100644 ui/src/app/core/reducer/message.reducer.ts create mode 100644 ui/src/app/core/service/i18n.service.ts diff --git a/backend/src/main/resources/i18n/messages_en-US.properties b/backend/src/main/resources/i18n/messages_en-US.properties new file mode 100644 index 000000000..2a91a9c2b --- /dev/null +++ b/backend/src/main/resources/i18n/messages_en-US.properties @@ -0,0 +1,11 @@ +action.dashboard=Dashboard (en-US) +action.logout=Logout +action.add-new=Add New +action.clear=Clear + +label.metadata-sources=Metadata Sources +label.metadata-source=Metadata Source +label.metadata-providers=Metadata Providers +label.metadata-provider=Metadata Provider +label.source-management=Source Management +label.search-files=Search Files diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 5c101832f..891e5be22 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -1 +1,11 @@ -a.sample.message=This is a sample message. \ No newline at end of file +action.dashboard=Dashboard (en) +action.logout=Logout +action.add-new=Add New +action.clear=Clear + +label.metadata-sources=Metadata Sources +label.metadata-source=Metadata Source +label.metadata-providers=Metadata Providers +label.metadata-provider=Metadata Provider +label.source-management=Source Management +label.search-files=Search Files diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index f3e44f399..981f95659 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -7,6 +7,9 @@ import { Store } from '@ngrx/store'; import * as fromRoot from './core/reducer'; import { VersionInfo } from './core/model/version'; import { VersionInfoLoadRequestAction } from './core/action/version.action'; +import { I18nService } from './core/service/i18n.service'; +import { SetLanguage } from './core/action/message.action'; + @Component({ selector: 'app-root', templateUrl: './app.component.html', @@ -21,12 +24,16 @@ export class AppComponent implements OnInit { formatter = v => v && v.build ? `${v.build.version}-${v.git.commit.id}` : ''; - constructor(private store: Store) { + constructor( + private store: Store, + private i18nService: I18nService + ) { this.version$ = this.store.select(fromRoot.getVersionInfo); this.formatted$ = this.version$.pipe(map(this.formatter)); } ngOnInit(): void { this.store.dispatch(new VersionInfoLoadRequestAction()); + this.store.dispatch(new SetLanguage(this.i18nService.getCurrentLanguage())); } } diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index aea2a20f6..b03c518e0 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -1,5 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { NgModule, LOCALE_ID } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; @@ -24,6 +24,7 @@ import { SharedModule } from './shared/shared.module'; import { WizardModule } from './wizard/wizard.module'; import { FormModule } from './schema-form/schema-form.module'; import { environment } from '../environments/environment.prod'; +import { getCurrentLanguage } from './shared/util'; @NgModule({ declarations: [ @@ -54,6 +55,7 @@ import { environment } from '../environments/environment.prod'; AppRoutingModule ], providers: [ + { provide: LOCALE_ID, useValue: getCurrentLanguage() }, NavigatorService, { provide: RouterStateSerializer, useClass: CustomRouterStateSerializer }, { diff --git a/ui/src/app/core/action/message.action.ts b/ui/src/app/core/action/message.action.ts new file mode 100644 index 000000000..131fd7e25 --- /dev/null +++ b/ui/src/app/core/action/message.action.ts @@ -0,0 +1,39 @@ +import { Action } from '@ngrx/store'; + +export enum MessagesActionTypes { + MESSAGES_LOAD_REQUEST = '[Messages] Load REQUEST', + MESSAGES_LOAD_SUCCESS = '[Messages] Load SUCCESS', + MESSAGES_LOAD_ERROR = '[Messages] Load ERROR', + + SET_LANGUAGE = '[Messages] Set Language' +} + +export class MessagesLoadRequestAction implements Action { + readonly type = MessagesActionTypes.MESSAGES_LOAD_REQUEST; + + constructor() { } +} + +export class MessagesLoadSuccessAction implements Action { + readonly type = MessagesActionTypes.MESSAGES_LOAD_SUCCESS; + + constructor(public payload: any) { } +} + +export class MessagesLoadErrorAction implements Action { + readonly type = MessagesActionTypes.MESSAGES_LOAD_ERROR; + + constructor(public payload: { message: string, type: string }) { } +} + +export class SetLanguage implements Action { + readonly type = MessagesActionTypes.SET_LANGUAGE; + + constructor(public payload: string) {} +} + +export type Actions = + | MessagesLoadRequestAction + | MessagesLoadSuccessAction + | MessagesLoadErrorAction + | SetLanguage; diff --git a/ui/src/app/core/core.module.ts b/ui/src/app/core/core.module.ts index b5606e630..a4ae326e7 100644 --- a/ui/src/app/core/core.module.ts +++ b/ui/src/app/core/core.module.ts @@ -14,6 +14,8 @@ import { UserEffects } from './effect/user.effect'; import { HttpClientModule } from '@angular/common/http'; import { ModalService } from './service/modal.service'; import { DifferentialService } from './service/differential.service'; +import { I18nService } from './service/i18n.service'; +import { MessageEffects } from './effect/message.effect'; export const COMPONENTS = []; @@ -36,7 +38,8 @@ export class CoreModule { FileService, ModalService, DifferentialService, - CanDeactivateGuard + CanDeactivateGuard, + I18nService ] }; } @@ -45,7 +48,7 @@ export class CoreModule { @NgModule({ imports: [ StoreModule.forFeature('core', reducers), - EffectsModule.forFeature([UserEffects, VersionEffects]), + EffectsModule.forFeature([UserEffects, VersionEffects, MessageEffects]), ], }) export class RootCoreModule { } diff --git a/ui/src/app/core/effect/message.effect.ts b/ui/src/app/core/effect/message.effect.ts new file mode 100644 index 000000000..e044ceb19 --- /dev/null +++ b/ui/src/app/core/effect/message.effect.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { Effect, Actions, ofType } from '@ngrx/effects'; + +import { of } from 'rxjs'; +import { map, catchError, switchMap, withLatestFrom } from 'rxjs/operators'; + +import { + MessagesActionTypes, + MessagesLoadErrorAction, + MessagesLoadRequestAction, + MessagesLoadSuccessAction, + SetLanguage +} from '../action/message.action'; +import { I18nService } from '../service/i18n.service'; +import * as fromCore from '../reducer'; +import { Store } from '@ngrx/store'; + +@Injectable() +export class MessageEffects { + + @Effect() + loadMessages$ = this.actions$.pipe( + ofType(MessagesActionTypes.MESSAGES_LOAD_REQUEST), + withLatestFrom(this.store.select(fromCore.getLanguage)), + switchMap(([action, lang]) => { + return this.i18nService.get(lang) + .pipe( + map(u => new MessagesLoadSuccessAction({ ...u })), + catchError(error => of(new MessagesLoadErrorAction(error))) + ); + }) + ); + @Effect() + setLanguage$ = this.actions$.pipe( + ofType(MessagesActionTypes.SET_LANGUAGE), + map(action => action.payload), + map(language => new MessagesLoadRequestAction()) + ); + + constructor( + private i18nService: I18nService, + private actions$: Actions, + private store: Store + ) { } +} diff --git a/ui/src/app/core/effect/user.effect.ts b/ui/src/app/core/effect/user.effect.ts index 4197547b9..72f3a8aac 100644 --- a/ui/src/app/core/effect/user.effect.ts +++ b/ui/src/app/core/effect/user.effect.ts @@ -1,12 +1,10 @@ import { Injectable } from '@angular/core'; import { Effect, Actions, ofType } from '@ngrx/effects'; -import { Location } from '@angular/common'; import { of } from 'rxjs'; import { map, tap, catchError, switchMap } from 'rxjs/operators'; import * as user from '../action/user.action'; -import { User } from '../model/user'; import { UserService } from '../service/user.service'; @Injectable() @@ -36,4 +34,4 @@ export class UserEffects { private userService: UserService, private actions$: Actions ) { } -} +} diff --git a/ui/src/app/core/reducer/index.ts b/ui/src/app/core/reducer/index.ts index de0686765..cec16b765 100644 --- a/ui/src/app/core/reducer/index.ts +++ b/ui/src/app/core/reducer/index.ts @@ -10,11 +10,13 @@ import { import * as fromUser from './user.reducer'; import * as fromVersion from './version.reducer'; +import * as fromMessages from './message.reducer'; import * as fromRoot from '../../app.reducer'; export interface CoreState { user: fromUser.UserState; version: fromVersion.VersionState; + messages: fromMessages.MessageState; } export interface State extends fromRoot.State { @@ -23,12 +25,14 @@ export interface State extends fromRoot.State { export const reducers = { user: fromUser.reducer, - version: fromVersion.reducer + version: fromVersion.reducer, + messages: fromMessages.reducer }; export const getCoreFeature = createFeatureSelector('core'); export const getUserStateFn = (state: CoreState) => state.user; export const getVersionStateFn = (state: CoreState) => state.version; +export const getMessageStateFn = (state: CoreState) => state.messages; export const getUserState = createSelector(getCoreFeature, getUserStateFn); export const getUser = createSelector(getUserState, fromUser.getUser); @@ -39,3 +43,8 @@ export const getVersionState = createSelector(getCoreFeature, (state: CoreState) export const getVersionInfo = createSelector(getVersionState, fromVersion.getVersionInfo); export const getVersionLoading = createSelector(getVersionState, fromVersion.getVersionIsLoading); export const getVersionError = createSelector(getVersionState, fromVersion.getVersionError); + +export const getMessageState = createSelector(getCoreFeature, getMessageStateFn); +export const getLanguage = createSelector(getMessageState, fromMessages.getLanguage); +export const getMessages = createSelector(getMessageState, fromMessages.getMessages); +export const getFetchingMessages = createSelector(getMessageState, fromMessages.isFetching); diff --git a/ui/src/app/core/reducer/message.reducer.ts b/ui/src/app/core/reducer/message.reducer.ts new file mode 100644 index 000000000..80dfe85c0 --- /dev/null +++ b/ui/src/app/core/reducer/message.reducer.ts @@ -0,0 +1,60 @@ +import { + MessagesActionTypes, + Actions, + +} from '../action/message.action'; + +export interface MessageState { + fetching: boolean; + messages: any; + error: any; + language: string; +} + +export const initialState: MessageState = { + fetching: false, + messages: null, + error: null, + language: 'en' +}; + +export function reducer(state = initialState, action: Actions): MessageState { + switch (action.type) { + case MessagesActionTypes.MESSAGES_LOAD_REQUEST: { + return { + ...state, + fetching: true + }; + } + case MessagesActionTypes.MESSAGES_LOAD_SUCCESS: { + return { + ...state, + fetching: false, + messages: action.payload + }; + } + case MessagesActionTypes.MESSAGES_LOAD_ERROR: { + return { + ...state, + fetching: false, + messages: null, + error: action.payload + }; + } + case MessagesActionTypes.SET_LANGUAGE: { + return { + ...state, + language: action.payload + }; + } + default: { + return state; + } + } +} + + +export const getMessages = (state: MessageState) => state.messages; +export const getLanguage = (state: MessageState) => state.language; +export const getError = (state: MessageState) => state.error; +export const isFetching = (state: MessageState) => state.fetching; diff --git a/ui/src/app/core/service/i18n.service.ts b/ui/src/app/core/service/i18n.service.ts new file mode 100644 index 000000000..9c5dccd5d --- /dev/null +++ b/ui/src/app/core/service/i18n.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { NavigatorService } from './navigator.service'; +import { getCurrentLanguage } from '../../shared/util'; + +@Injectable() +export class I18nService { + + readonly path = '/messages'; + readonly base = '/api'; + + constructor( + private http: HttpClient, + private navigator: NavigatorService + ) {} + + get(language: string = null): Observable { + let params: HttpParams = new HttpParams(); + if (!!language) { + params = params.set('lang', language); + } + return this.http.get(`${ this.base }${this.path}`, { + params + }); + } + + getCurrentLanguage(): string { + return getCurrentLanguage(this.navigator.native); + } +} diff --git a/ui/src/app/shared/util.ts b/ui/src/app/shared/util.ts index 4224f5b8a..88041c15f 100644 --- a/ui/src/app/shared/util.ts +++ b/ui/src/app/shared/util.ts @@ -61,3 +61,45 @@ export function array_move(arr, old_index, new_index): any[] { arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); return arr; } + +export function getCurrentLanguage(nav: any = null): string { + nav = nav || navigator; + const getLocaleId = (lang: string) => lang.trim(); + // supported regional languages + const supportedLanguages: string[] = ['en', 'es', 'en-US', 'es-ES'].map(lang => getLocaleId(lang)); + // language code without regional details + const shortSupportedLanguages: string[] = supportedLanguages.map(lang => lang.substring(0, 2)); + + // look for an exact match to a regional translation + let preferredLanguage = getLocaleId(nav.language); + if (supportedLanguages.includes(preferredLanguage)) { + return preferredLanguage; + } + + // for language only match, no regional details + let shortPreferredLanguage: string = preferredLanguage.substring(0, 2); + let index = shortSupportedLanguages.indexOf(shortPreferredLanguage); + if (index > -1) { + return supportedLanguages[index]; + } + + // not all browsers share full language list + if (nav.languages instanceof Array) { + // get list of all languages user understands, check for an exact regional match + const allPreferredLanugages: string[] = nav.languages.map(lang => getLocaleId(lang)); + preferredLanguage = allPreferredLanugages.find(language => supportedLanguages.includes(language)); + if (preferredLanguage) { + return preferredLanguage; + } + + // from list of all languages user understand, check for language only match + const shortAllPreferredLanugages: string[] = allPreferredLanugages.map(language => language.substring(0, 2)); + index = shortAllPreferredLanugages.findIndex(language => shortSupportedLanguages.includes(language)); + if (index > -1) { + return supportedLanguages[index]; + } + } + + // if no match has been found return first (default) language + return supportedLanguages[0]; +} From 876efe8aa52251fb0a2643e8bed43eba324c9299 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 6 Sep 2018 14:13:38 -0700 Subject: [PATCH 03/23] SHIBUI-814 Implemented service for messages --- .../resources/i18n/messages_en-US.properties | 11 ----------- ui/src/app/app.component.ts | 4 ++-- ui/src/app/app.module.ts | 4 ++-- ui/src/app/core/action/message.action.ts | 8 ++++---- ui/src/app/core/effect/message.effect.ts | 17 ++++++++++------- ui/src/app/core/reducer/index.ts | 6 +++++- ui/src/app/core/reducer/message.reducer.ts | 10 +++++----- ui/src/app/core/service/i18n.service.ts | 16 +++++++++++----- ui/src/app/shared/util.ts | 10 +++++++++- 9 files changed, 48 insertions(+), 38 deletions(-) delete mode 100644 backend/src/main/resources/i18n/messages_en-US.properties diff --git a/backend/src/main/resources/i18n/messages_en-US.properties b/backend/src/main/resources/i18n/messages_en-US.properties deleted file mode 100644 index 2a91a9c2b..000000000 --- a/backend/src/main/resources/i18n/messages_en-US.properties +++ /dev/null @@ -1,11 +0,0 @@ -action.dashboard=Dashboard (en-US) -action.logout=Logout -action.add-new=Add New -action.clear=Clear - -label.metadata-sources=Metadata Sources -label.metadata-source=Metadata Source -label.metadata-providers=Metadata Providers -label.metadata-provider=Metadata Provider -label.source-management=Source Management -label.search-files=Search Files diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 981f95659..3a43405b4 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -8,7 +8,7 @@ import * as fromRoot from './core/reducer'; import { VersionInfo } from './core/model/version'; import { VersionInfoLoadRequestAction } from './core/action/version.action'; import { I18nService } from './core/service/i18n.service'; -import { SetLanguage } from './core/action/message.action'; +import { SetLocale } from './core/action/message.action'; @Component({ selector: 'app-root', @@ -34,6 +34,6 @@ export class AppComponent implements OnInit { ngOnInit(): void { this.store.dispatch(new VersionInfoLoadRequestAction()); - this.store.dispatch(new SetLanguage(this.i18nService.getCurrentLanguage())); + this.store.dispatch(new SetLocale(this.i18nService.getCurrentLocale())); } } diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index b03c518e0..140e0df1c 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -24,7 +24,7 @@ import { SharedModule } from './shared/shared.module'; import { WizardModule } from './wizard/wizard.module'; import { FormModule } from './schema-form/schema-form.module'; import { environment } from '../environments/environment.prod'; -import { getCurrentLanguage } from './shared/util'; +import { getCurrentLocale } from './shared/util'; @NgModule({ declarations: [ @@ -55,7 +55,7 @@ import { getCurrentLanguage } from './shared/util'; AppRoutingModule ], providers: [ - { provide: LOCALE_ID, useValue: getCurrentLanguage() }, + { provide: LOCALE_ID, useValue: getCurrentLocale(null) }, NavigatorService, { provide: RouterStateSerializer, useClass: CustomRouterStateSerializer }, { diff --git a/ui/src/app/core/action/message.action.ts b/ui/src/app/core/action/message.action.ts index 131fd7e25..49b274957 100644 --- a/ui/src/app/core/action/message.action.ts +++ b/ui/src/app/core/action/message.action.ts @@ -5,7 +5,7 @@ export enum MessagesActionTypes { MESSAGES_LOAD_SUCCESS = '[Messages] Load SUCCESS', MESSAGES_LOAD_ERROR = '[Messages] Load ERROR', - SET_LANGUAGE = '[Messages] Set Language' + SET_LOCALE = '[Messages] Set Locale' } export class MessagesLoadRequestAction implements Action { @@ -26,8 +26,8 @@ export class MessagesLoadErrorAction implements Action { constructor(public payload: { message: string, type: string }) { } } -export class SetLanguage implements Action { - readonly type = MessagesActionTypes.SET_LANGUAGE; +export class SetLocale implements Action { + readonly type = MessagesActionTypes.SET_LOCALE; constructor(public payload: string) {} } @@ -36,4 +36,4 @@ export type Actions = | MessagesLoadRequestAction | MessagesLoadSuccessAction | MessagesLoadErrorAction - | SetLanguage; + | SetLocale; diff --git a/ui/src/app/core/effect/message.effect.ts b/ui/src/app/core/effect/message.effect.ts index e044ceb19..04efbe330 100644 --- a/ui/src/app/core/effect/message.effect.ts +++ b/ui/src/app/core/effect/message.effect.ts @@ -9,7 +9,7 @@ import { MessagesLoadErrorAction, MessagesLoadRequestAction, MessagesLoadSuccessAction, - SetLanguage + SetLocale } from '../action/message.action'; import { I18nService } from '../service/i18n.service'; import * as fromCore from '../reducer'; @@ -21,18 +21,21 @@ export class MessageEffects { @Effect() loadMessages$ = this.actions$.pipe( ofType(MessagesActionTypes.MESSAGES_LOAD_REQUEST), - withLatestFrom(this.store.select(fromCore.getLanguage)), - switchMap(([action, lang]) => { - return this.i18nService.get(lang) + withLatestFrom( + this.store.select(fromCore.getLocale) + ), + map(([action, locale]) => locale.replace('-', '_')), + switchMap(locale => + this.i18nService.get(locale) .pipe( map(u => new MessagesLoadSuccessAction({ ...u })), catchError(error => of(new MessagesLoadErrorAction(error))) - ); - }) + ) + ) ); @Effect() setLanguage$ = this.actions$.pipe( - ofType(MessagesActionTypes.SET_LANGUAGE), + ofType(MessagesActionTypes.SET_LOCALE), map(action => action.payload), map(language => new MessagesLoadRequestAction()) ); diff --git a/ui/src/app/core/reducer/index.ts b/ui/src/app/core/reducer/index.ts index cec16b765..1f1b89960 100644 --- a/ui/src/app/core/reducer/index.ts +++ b/ui/src/app/core/reducer/index.ts @@ -12,6 +12,7 @@ import * as fromUser from './user.reducer'; import * as fromVersion from './version.reducer'; import * as fromMessages from './message.reducer'; import * as fromRoot from '../../app.reducer'; +import { getCurrentLanguage, getCurrentCountry } from '../../shared/util'; export interface CoreState { user: fromUser.UserState; @@ -45,6 +46,9 @@ export const getVersionLoading = createSelector(getVersionState, fromVersion.get export const getVersionError = createSelector(getVersionState, fromVersion.getVersionError); export const getMessageState = createSelector(getCoreFeature, getMessageStateFn); -export const getLanguage = createSelector(getMessageState, fromMessages.getLanguage); +export const getLocale = createSelector(getMessageState, fromMessages.getLocale); +export const getLanguage = createSelector(getLocale, locale => getCurrentLanguage(locale)); +export const getCountry = createSelector(getLocale, locale => getCurrentCountry(locale)); + export const getMessages = createSelector(getMessageState, fromMessages.getMessages); export const getFetchingMessages = createSelector(getMessageState, fromMessages.isFetching); diff --git a/ui/src/app/core/reducer/message.reducer.ts b/ui/src/app/core/reducer/message.reducer.ts index 80dfe85c0..a57bdb4c6 100644 --- a/ui/src/app/core/reducer/message.reducer.ts +++ b/ui/src/app/core/reducer/message.reducer.ts @@ -8,14 +8,14 @@ export interface MessageState { fetching: boolean; messages: any; error: any; - language: string; + locale: string; } export const initialState: MessageState = { fetching: false, messages: null, error: null, - language: 'en' + locale: null }; export function reducer(state = initialState, action: Actions): MessageState { @@ -41,10 +41,10 @@ export function reducer(state = initialState, action: Actions): MessageState { error: action.payload }; } - case MessagesActionTypes.SET_LANGUAGE: { + case MessagesActionTypes.SET_LOCALE: { return { ...state, - language: action.payload + locale: action.payload }; } default: { @@ -55,6 +55,6 @@ export function reducer(state = initialState, action: Actions): MessageState { export const getMessages = (state: MessageState) => state.messages; -export const getLanguage = (state: MessageState) => state.language; +export const getLocale = (state: MessageState) => state.locale; export const getError = (state: MessageState) => state.error; export const isFetching = (state: MessageState) => state.fetching; diff --git a/ui/src/app/core/service/i18n.service.ts b/ui/src/app/core/service/i18n.service.ts index 9c5dccd5d..d92cfa99d 100644 --- a/ui/src/app/core/service/i18n.service.ts +++ b/ui/src/app/core/service/i18n.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient, HttpParams } from '@angular/common/http'; import { NavigatorService } from './navigator.service'; -import { getCurrentLanguage } from '../../shared/util'; +import { getCurrentLanguage, getCurrentCountry, getCurrentLocale } from '../../shared/util'; @Injectable() export class I18nService { @@ -15,11 +15,9 @@ export class I18nService { private navigator: NavigatorService ) {} - get(language: string = null): Observable { + get(locale: string): Observable { let params: HttpParams = new HttpParams(); - if (!!language) { - params = params.set('lang', language); - } + params = params.set('lang', locale); return this.http.get(`${ this.base }${this.path}`, { params }); @@ -28,4 +26,12 @@ export class I18nService { getCurrentLanguage(): string { return getCurrentLanguage(this.navigator.native); } + + getCurrentCountry(): string { + return getCurrentCountry(this.navigator.native); + } + + getCurrentLocale(): string { + return getCurrentLocale(this.navigator.native); + } } diff --git a/ui/src/app/shared/util.ts b/ui/src/app/shared/util.ts index 88041c15f..9dc647dc5 100644 --- a/ui/src/app/shared/util.ts +++ b/ui/src/app/shared/util.ts @@ -62,7 +62,15 @@ export function array_move(arr, old_index, new_index): any[] { return arr; } -export function getCurrentLanguage(nav: any = null): string { +export function getCurrentLanguage(locale: string): string { + return getCurrentLocale(locale).split('-', 1)[0]; +} + +export function getCurrentCountry(locale: string): string { + return getCurrentLocale(locale).split('-', 1)[1]; +} + +export function getCurrentLocale(nav: any = null): string { nav = nav || navigator; const getLocaleId = (lang: string) => lang.trim(); // supported regional languages From 19d96f4fe9ce349e15a5b8f8407bf076cf962112 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Wed, 12 Sep 2018 09:11:34 -0700 Subject: [PATCH 04/23] SHIBUI-814 Fixed tests, implemented pipe for i18n --- .../resources/i18n/messages_en.properties | 2 + ui/src/app/app.component.html | 2 +- ui/src/app/app.component.spec.ts | 12 ++-- ui/src/app/app.component.ts | 4 +- ui/src/app/app.module.ts | 3 + ui/src/app/core/core.module.ts | 7 +- ui/src/app/core/reducer/index.ts | 22 +----- .../{core => i18n}/action/message.action.ts | 0 .../{core => i18n}/effect/message.effect.ts | 0 ui/src/app/i18n/i18n.module.ts | 53 ++++++++++++++ ui/src/app/i18n/pipe/i18n.pipe.spec.ts | 72 +++++++++++++++++++ ui/src/app/i18n/pipe/i18n.pipe.ts | 40 +++++++++++ ui/src/app/i18n/reducer/index.ts | 31 ++++++++ .../{core => i18n}/reducer/message.reducer.ts | 0 .../{core => i18n}/service/i18n.service.ts | 9 ++- ui/src/testing/i18n.stub.ts | 48 +++++++++++++ 16 files changed, 272 insertions(+), 33 deletions(-) rename ui/src/app/{core => i18n}/action/message.action.ts (100%) rename ui/src/app/{core => i18n}/effect/message.effect.ts (100%) create mode 100644 ui/src/app/i18n/i18n.module.ts create mode 100644 ui/src/app/i18n/pipe/i18n.pipe.spec.ts create mode 100644 ui/src/app/i18n/pipe/i18n.pipe.ts create mode 100644 ui/src/app/i18n/reducer/index.ts rename ui/src/app/{core => i18n}/reducer/message.reducer.ts (100%) rename ui/src/app/{core => i18n}/service/i18n.service.ts (71%) create mode 100644 ui/src/testing/i18n.stub.ts diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 891e5be22..b9f3e0049 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -3,6 +3,8 @@ action.logout=Logout action.add-new=Add New action.clear=Clear +heading.shibboleth=Shibboleth { foo } + label.metadata-sources=Metadata Sources label.metadata-source=Metadata Source label.metadata-providers=Metadata Providers diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 17b5742e3..224f69d34 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -2,7 +2,7 @@