Translate of HR Information is implemented

This commit is contained in:
병준 박 2019-12-17 15:13:25 +09:00
parent 4e2f19b91e
commit 9441a1304c
23 changed files with 422 additions and 179 deletions

View File

@ -8,7 +8,10 @@ import {
import { Store } from '@ngrx/store';
import { DialogService } from '@ucap-webmessenger/ui';
import {
DialogService,
TranslateService as UCapTranslateService
} from '@ucap-webmessenger/ui';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { map } from 'rxjs/operators';
@ -44,6 +47,7 @@ export class MessengerSettingsDialogComponent implements OnInit {
private dialogService: DialogService,
private sessionStorageService: SessionStorageService,
private localStorageService: LocalStorageService,
private ucapTranslateService: UCapTranslateService,
private store: Store<any>,
@Inject(DOCUMENT) private document: Document,
private renderer2: Renderer2
@ -71,6 +75,13 @@ export class MessengerSettingsDialogComponent implements OnInit {
setting.appTheme
);
}
if (this.appUserInfo.settings.general.locale !== setting.locale) {
}
if (
this.appUserInfo.settings.general.hrInfoLocale !== setting.hrInfoLocale
) {
this.ucapTranslateService.use(setting.hrInfoLocale);
}
this.applySettings({ ...this.appUserInfo.settings, general: setting });
}

View File

@ -42,6 +42,8 @@ import { NGXLogger } from 'ngx-logger';
import { QueryProtocolService } from '@ucap-webmessenger/protocol-query';
import { OptionProtocolService } from '@ucap-webmessenger/protocol-option';
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
import * as AppStore from '@app/store';
import * as CompanyStore from '@app/store/setting/company';
import * as VersionInfoStore from '@app/store/setting/version-info';

View File

@ -6,6 +6,8 @@ import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types';
import { AppNotificationService } from './notification.service';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { AppNativeService } from './native.service';
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
import { TranslateService } from '@ngx-translate/core';
@Injectable()
export class AppService {
@ -14,8 +16,16 @@ export class AppService {
private sessionStorageService: SessionStorageService,
private appNotificationService: AppNotificationService,
private appNativeService: AppNativeService,
// private translateService: TranslateService,
private ucapTranslateService: UCapTranslateService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService
) {}
) {
// this.translateService.setDefaultLang('ko');
// this.translateService.use('ko');
this.ucapTranslateService.setDefaultLang('ko');
this.ucapTranslateService.use('ko');
}
public postInit(): Promise<any> {
const initPromise = new Promise<void>((resolve, reject) => {

View File

@ -13,6 +13,7 @@ import {
KEY_URL_INFO
} from '../types';
import { PasswordUtil } from '@ucap-webmessenger/pi';
import { DaesangCipherService } from '@ucap-webmessenger/daesang';
import { environment } from '../../environments/environment';

View File

@ -1,6 +1,38 @@
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
import { map, tap } from 'rxjs/operators';
import * as AuthenticationStore from '@app/store/account/authentication';
import { LocalStorageService } from '@ucap-webmessenger/web-storage';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { environment } from '../../../../environments/environment';
@Injectable()
export class Effects {
constructor() {}
postLogin$ = createEffect(
() =>
this.actions$.pipe(
ofType(AuthenticationStore.postLogin),
map(action => action.loginRes),
tap(async loginRes => {
const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
KEY_APP_USER_INFO,
environment.customConfig.appKey
);
this.ucapTranslateService.use(
appUserInfo.settings.general.hrInfoLocale
);
})
),
{ dispatch: false }
);
constructor(
private actions$: Actions,
private ucapTranslateService: UCapTranslateService,
private localStorageService: LocalStorageService
) {}
}

View File

@ -43,6 +43,7 @@ export const environment: Environment = {
autoStart: true,
continueRunWhenClose: true,
locale: 'ko',
hrInfoLocale: 'ko',
startBackgroudMode: false,
timezone: '+9'
},

View File

@ -43,6 +43,7 @@ export const environment: Environment = {
autoStart: true,
continueRunWhenClose: true,
locale: 'ko',
hrInfoLocale: 'ko',
startBackgroudMode: false,
timezone: '+9'
},

View File

@ -43,6 +43,7 @@ export const environment: Environment = {
autoStart: true,
continueRunWhenClose: true,
locale: 'ko',
hrInfoLocale: 'ko',
startBackgroudMode: false,
timezone: '+9'
},

View File

@ -43,6 +43,7 @@ export const environment: Environment = {
autoStart: true,
continueRunWhenClose: true,
locale: 'ko',
hrInfoLocale: 'ko',
startBackgroudMode: false,
timezone: '+9'
},

View File

@ -39,7 +39,9 @@
</div>
<li (click)="onClickNode(node)" matRipple>
<div class="tree-node-body">{{ node.name }}</div>
<div class="tree-node-body">
{{ node.deptInfo | ucapTranslate: 'name' }}
</div>
</li>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
@ -83,7 +85,9 @@
{{ treeControl.isExpanded(node) ? 'remove' : 'add' }}
</mat-icon>
</button>
<span class="dept-name">{{ node.name }}</span>
<span class="dept-name">{{
node.deptInfo | ucapTranslate: 'name'
}}</span>
</div>
<!-- <ul class="tree-node-closer"></ul> -->
</li>

View File

@ -1,164 +0,0 @@
import {
ChangeDetectorRef,
Injectable,
OnDestroy,
Pipe,
PipeTransform
} from '@angular/core';
import {
LangChangeEvent,
TranslateService,
TranslationChangeEvent
} from '@ngx-translate/core';
import { ObjectUtil } from '@ucap-webmessenger/core';
import { Subscription } from 'rxjs';
@Injectable()
@Pipe({
name: 'ucap-organization-translate',
pure: false // required to update the value when the promise is resolved
})
export class TranslatePipe implements PipeTransform, OnDestroy {
value = '';
lastKey: string;
lastParams: any[];
onTranslationChange: Subscription;
onLangChange: Subscription;
onDefaultLangChange: Subscription;
constructor(
private translate: TranslateService,
private changeDetectorRef: ChangeDetectorRef
) {}
updateValue(
key: string,
interpolateParams?: object,
translations?: any
): void {
const onTranslation = (res: string) => {
this.value = res !== undefined ? res : key;
this.lastKey = key;
this.changeDetectorRef.markForCheck();
};
if (translations) {
const res = this.translate.getParsedResult(
translations,
key,
interpolateParams
);
if (typeof res.subscribe === 'function') {
res.subscribe(onTranslation);
} else {
onTranslation(res);
}
}
this.translate.get(key, interpolateParams).subscribe(onTranslation);
}
transform(query: string, ...args: any[]): any {
if (!query || query.length === 0) {
return query;
}
// if we ask another time for the same key, return the last value
if (
ObjectUtil.equals(query, this.lastKey) &&
ObjectUtil.equals(args, this.lastParams)
) {
return this.value;
}
let interpolateParams: object;
if (!!args[0] && args.length) {
if (typeof args[0] === 'string' && args[0].length) {
// we accept objects written in the template such as {n:1}, {'n':1}, {n:'v'}
// which is why we might need to change it to real JSON objects such as {"n":1} or {"n":"v"}
const validArgs: string = args[0]
.replace(/(\')?([a-zA-Z0-9_]+)(\')?(\s)?:/g, '"$2":')
.replace(/:(\s)?(\')(.*?)(\')/g, ':"$3"');
try {
interpolateParams = JSON.parse(validArgs);
} catch (e) {
throw new SyntaxError(
`Wrong parameter in TranslatePipe. Expected a valid Object, received: ${args[0]}`
);
}
} else if (typeof args[0] === 'object' && !Array.isArray(args[0])) {
interpolateParams = args[0];
}
}
// store the query, in case it changes
this.lastKey = query;
// store the params, in case they change
this.lastParams = args;
// set the value
this.updateValue(query, interpolateParams);
// if there is a subscription to onLangChange, clean it
this._dispose();
// subscribe to onTranslationChange event, in case the translations change
if (!this.onTranslationChange) {
this.onTranslationChange = this.translate.onTranslationChange.subscribe(
(event: TranslationChangeEvent) => {
if (this.lastKey && event.lang === this.translate.currentLang) {
this.lastKey = null;
this.updateValue(query, interpolateParams, event.translations);
}
}
);
}
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChange) {
this.onLangChange = this.translate.onLangChange.subscribe(
(event: LangChangeEvent) => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, interpolateParams, event.translations);
}
}
);
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChange) {
this.onDefaultLangChange = this.translate.onDefaultLangChange.subscribe(
() => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, interpolateParams);
}
}
);
}
return this.value;
}
/**
* Clean any existing subscription to change events
*/
private _dispose(): void {
if (typeof this.onTranslationChange !== 'undefined') {
this.onTranslationChange.unsubscribe();
this.onTranslationChange = undefined;
}
if (typeof this.onLangChange !== 'undefined') {
this.onLangChange.unsubscribe();
this.onLangChange = undefined;
}
if (typeof this.onDefaultLangChange !== 'undefined') {
this.onDefaultLangChange.unsubscribe();
this.onDefaultLangChange = undefined;
}
}
ngOnDestroy(): void {
this._dispose();
}
}

View File

@ -16,6 +16,8 @@ import { MatTreeModule } from '@angular/material/tree';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { UCapUiModule } from '@ucap-webmessenger/ui';
import { TenantSearchComponent } from './components/tenant-search.component';
import { TreeComponent } from './components/tree.component';
@ -37,7 +39,9 @@ const SERVICES = [];
MatSelectModule,
MatTreeModule,
PerfectScrollbarModule
PerfectScrollbarModule,
UCapUiModule
],
exports: [...COMPONENTS],
declarations: [...COMPONENTS]

View File

@ -1,10 +1,12 @@
<mat-card class="example-card mat-elevation-z">
<mat-card-header>
<mat-card-title>
<span>{{ userInfo.name }}</span>
<span>{{ userInfo.grade }}</span>
<span>{{ userInfo | ucapTranslate: 'name' }}</span>
<span>{{ userInfo | ucapTranslate: 'grade' }}</span>
</mat-card-title>
<mat-card-subtitle>{{ userInfo.deptName }}</mat-card-subtitle>
<mat-card-subtitle>{{
userInfo | ucapTranslate: 'deptName'
}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>

View File

@ -16,11 +16,11 @@
<dd class="info">
<div class="detail">
<span class="name">
<b>{{ userInfo.name }}</b>
{{ userInfo.grade }}
<b>{{ userInfo | ucapTranslate: 'name' }}</b>
{{ userInfo | ucapTranslate: 'grade' }}
</span>
<span class="dept">
{{ userInfo.deptName }}
{{ userInfo | ucapTranslate: 'deptName' }}
</span>
</div>
<!-- 상태메시지 제외

View File

@ -24,7 +24,25 @@
<dd class="info">
<div class="detail">
<div class="room-name">
<div class="name">{{ getRoomName(roomInfo) }}</div>
<div class="name">
<ng-template
[ngIf]="!!roomInfo.roomName && '' !== roomInfo.roomName.trim()"
[ngIfElse]="roomNameNotExist"
>
{{ roomInfo.roomName }}
</ng-template>
<ng-template #roomNameNotExist>
<ng-template
[ngIf]="RoomType.Mytalk === roomInfo.roomType"
[ngIfElse]="roomNameByUserNames"
>Second</ng-template
>
</ng-template>
<ng-template #roomNameByUserNames>
{{ _roomUserInfos | ucapTranslate: 'name':',' }}
</ng-template>
<!-- {{ getRoomName(roomInfo) }} -->
</div>
<div
class="num bg-accent-light"
*ngIf="roomInfo.roomType === RoomType.Multi"

View File

@ -114,6 +114,14 @@ export class ListItemComponent implements OnInit {
}
}
get _roomUserInfos() {
return this.roomUserInfo.filter(roomUserInfo => {
return (
this.loginRes.userSeq !== roomUserInfo.seq && !!roomUserInfo.isJoinRoom
);
});
}
// getChecked(value: boolean, roomInfo: RoomInfo) {
// if (value && !this.multiCheckable) {
// if (this.selected === roomInfo.roomSeq) {

View File

@ -92,6 +92,25 @@
<mat-divider></mat-divider>
<h1 mat-subheader>인사 정보 언어</h1>
<mat-list-item>
<mat-form-field fxFlexFill>
<mat-select
[value]="setting.hrInfoLocale"
(selectionChange)="onSelectionChangeHrInfoLocale($event)"
>
<mat-option value="ko">
한국어 (대한민국)
</mat-option>
<mat-option value="en">
영어 (미국)
</mat-option>
</mat-select>
</mat-form-field>
</mat-list-item>
<mat-divider></mat-divider>
<h1 mat-subheader>시간대</h1>
<mat-list-item>
<mat-form-field fxFlexFill>

View File

@ -81,6 +81,10 @@ export class GeneralComponent implements OnInit {
this.emit({ ...this.setting, locale: event.value });
}
onSelectionChangeHrInfoLocale(event: MatSelectChange) {
this.emit({ ...this.setting, hrInfoLocale: event.value });
}
onSelectionChangeTimezone(event: MatSelectChange) {
this.emit({ ...this.setting, timezone: event.value });
}

View File

@ -5,6 +5,7 @@ export interface GeneralSetting {
continueRunWhenClose: boolean;
autoLogin: boolean;
locale: string;
hrInfoLocale: string;
timezone: string;
}

View File

@ -0,0 +1,121 @@
import {
ChangeDetectorRef,
Injectable,
OnDestroy,
Pipe,
PipeTransform
} from '@angular/core';
import { Subscription } from 'rxjs';
import { ObjectUtil } from '@ucap-webmessenger/core';
import {
TranslateService,
LangChangeEvent
} from '../services/translate.service';
@Injectable()
@Pipe({
name: 'ucapTranslate',
pure: false // required to update the value when the promise is resolved
})
export class TranslatePipe implements PipeTransform, OnDestroy {
value = '';
lastTarget: any;
lastKey: string;
lastSeparator: string;
onLangChange: Subscription;
onDefaultLangChange: Subscription;
constructor(
private translateService: TranslateService,
private changeDetectorRef: ChangeDetectorRef
) {}
updateValue(target: any, key: string, separator?: string): void {
try {
const value = this.translateService.get(target, key, separator);
this.value = value;
} catch (error) {
this.value = key;
}
this.lastTarget = target;
this.lastKey = key;
this.changeDetectorRef.markForCheck();
}
transform(target: any, key: string, separator?: string): any {
if (
!target ||
0 === Object.keys(target).length ||
!key ||
0 === key.length
) {
return '';
}
// if we ask another time for the same key, return the last value
if (
ObjectUtil.equals(target, this.lastTarget) &&
ObjectUtil.equals(key, this.lastKey) &&
ObjectUtil.equals(separator, this.lastSeparator)
) {
return this.value;
}
// store the target, in case it changes
this.lastTarget = target;
// store the key, in case it changes
this.lastKey = key;
// store the key, in case it changes
this.lastSeparator = separator;
// set the value
this.updateValue(target, key, separator);
// if there is a subscription to onLangChange, clean it
this._dispose();
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChange) {
this.onLangChange = this.translateService.onLangChange.subscribe(
(event: LangChangeEvent) => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(target, key, separator);
}
}
);
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChange) {
this.onDefaultLangChange = this.translateService.onDefaultLangChange.subscribe(
() => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(target, key, separator);
}
}
);
}
return this.value;
}
/**
* Clean any existing subscription to change events
*/
private _dispose(): void {
if (typeof this.onLangChange !== 'undefined') {
this.onLangChange.unsubscribe();
this.onLangChange = undefined;
}
if (typeof this.onDefaultLangChange !== 'undefined') {
this.onDefaultLangChange.unsubscribe();
this.onDefaultLangChange = undefined;
}
}
ngOnDestroy(): void {
this._dispose();
}
}

View File

@ -0,0 +1,161 @@
import { Injectable, EventEmitter } from '@angular/core';
export interface LangChangeEvent {
lang: string;
}
export interface DefaultLangChangeEvent {
lang: string;
}
@Injectable({
providedIn: 'root'
})
export class TranslateService {
// tslint:disable-next-line: variable-name
private _onLangChange: EventEmitter<LangChangeEvent> = new EventEmitter<
LangChangeEvent
>();
// tslint:disable-next-line: variable-name
private _onDefaultLangChange: EventEmitter<
DefaultLangChangeEvent
> = new EventEmitter<DefaultLangChangeEvent>();
// tslint:disable-next-line: variable-name
private _defaultLang: string;
// tslint:disable-next-line: variable-name
private _currentLang: string;
/**
* An EventEmitter to listen to lang change events
* onLangChange.subscribe((params: LangChangeEvent) => {
* // do something
* });
*/
get onLangChange(): EventEmitter<LangChangeEvent> {
return this._onLangChange;
}
/**
* An EventEmitter to listen to default lang change events
* onDefaultLangChange.subscribe((params: DefaultLangChangeEvent) => {
* // do something
* });
*/
get onDefaultLangChange() {
return this._onDefaultLangChange;
}
/**
* The default lang to fallback when translations are missing on the current lang
*/
get defaultLang(): string {
return this._defaultLang;
}
set defaultLang(defaultLang: string) {
this._defaultLang = defaultLang;
}
/**
* The lang currently used
*/
get currentLang(): string {
return this._currentLang;
}
set currentLang(currentLang: string) {
this._currentLang = currentLang;
}
constructor() {}
/**
* Sets the default language to use as a fallback
*/
public setDefaultLang(lang: string): void {
if (lang === this.defaultLang) {
return;
}
this.changeDefaultLang(lang);
}
/**
* Gets the default language used
*/
public getDefaultLang(): string {
return this.defaultLang;
}
/**
* Changes the lang currently used
*/
public use(lang: string): void {
// don't change the language if the language given is already selected
if (lang === this.currentLang) {
return;
}
this.changeLang(lang);
}
/**
* Gets the translated value of a key (or an array of keys)
* @returns the translated key, or an object of translated keys
*/
public get(target: any, key: string, separator?: string): string {
if (!target || 0 === Object.keys(target).length) {
throw new Error(`Parameter "target" is not valid`);
}
if (!key || 0 === key.length) {
throw new Error(`Parameter "key" required`);
}
if (target instanceof Array) {
const result: string[] = [];
target.forEach(t => {
result.push(this.get(t, key, separator));
});
return result.join(!!separator ? separator : '');
}
const keys = Object.keys(target);
try {
const lang =
this.currentLang.charAt(0).toUpperCase() +
this.currentLang.substring(1);
const langKey = `${key}${lang}`;
if (-1 !== keys.indexOf(langKey)) {
return target[langKey];
}
} catch (error) {}
if (-1 !== keys.indexOf(key)) {
return target[key];
}
throw new Error(`value is not exist`);
}
/**
* Changes the current lang
*/
private changeLang(lang: string): void {
this.currentLang = lang;
this.onLangChange.emit({ lang });
// if there is no default lang, use the one that we just set
if (!this.defaultLang) {
this.changeDefaultLang(lang);
}
}
/**
* Changes the default lang
*/
private changeDefaultLang(lang: string): void {
this.defaultLang = lang;
this.onDefaultLangChange.emit({ lang });
}
}

View File

@ -43,6 +43,7 @@ import { ClipboardService } from './services/clipboard.service';
import { DialogService } from './services/dialog.service';
import { SnackBarService } from './services/snack-bar.service';
import { SplashScreenService } from './services/splash-screen.service';
import { TranslateService } from './services/translate.service';
import { ClickOutsideDirective } from './directives/click-outside.directive';
import { FileUploadForDirective } from './directives/file-upload-for.directive';
@ -61,6 +62,7 @@ import {
} from './pipes/dates.pipe';
import { SecondsToMinutesPipe } from './pipes/seconds-to-minutes.pipe';
import { LinkyPipe } from './pipes/linky.pipe';
import { TranslatePipe } from './pipes/translate.pipe';
import { MatTabsModule } from '@angular/material';
@ -96,14 +98,16 @@ const PIPES = [
DateToStringFormatPipe,
DateDistanceToDatePipe,
SecondsToMinutesPipe,
LinkyPipe
LinkyPipe,
TranslatePipe
];
const SERVICES = [
BottomSheetService,
ClipboardService,
DialogService,
SnackBarService,
SplashScreenService
SplashScreenService,
TranslateService
];
@NgModule({

View File

@ -33,6 +33,7 @@ export * from './lib/services/clipboard.service';
export * from './lib/services/dialog.service';
export * from './lib/services/snack-bar.service';
export * from './lib/services/splash-screen.service';
export * from './lib/services/translate.service';
export * from './lib/types/file-viewer.type';