From d78e015ba0f6e0d7dcdccc7d2efebbb6dae420e5 Mon Sep 17 00:00:00 2001 From: Richard Park Date: Mon, 16 Dec 2019 05:20:52 +0900 Subject: [PATCH] translate of organization is added --- .../src/lib/utils/object.util.ts | 56 ++++++ .../ucap-webmessenger-core/src/public-api.ts | 1 + .../src/lib/pipes/translate.pipe.ts | 164 ++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 projects/ucap-webmessenger-core/src/lib/utils/object.util.ts create mode 100644 projects/ucap-webmessenger-ui-organization/src/lib/pipes/translate.pipe.ts diff --git a/projects/ucap-webmessenger-core/src/lib/utils/object.util.ts b/projects/ucap-webmessenger-core/src/lib/utils/object.util.ts new file mode 100644 index 00000000..e6dcc930 --- /dev/null +++ b/projects/ucap-webmessenger-core/src/lib/utils/object.util.ts @@ -0,0 +1,56 @@ +export class ObjectUtil { + static equals(o1: any, o2: any): boolean { + if (o1 === o2) { + return true; + } + if (o1 === null || o2 === null) { + return false; + } + if (o1 !== o1 && o2 !== o2) { + return true; // NaN === NaN + } + const t1 = typeof o1; + const t2 = typeof o2; + let length: number; + let key: any; + let keySet: any; + if (t1 === t2 && t1 === 'object') { + if (Array.isArray(o1)) { + if (!Array.isArray(o2)) { + return false; + } + length = o1.length; + if (length === o2.length) { + for (key = 0; key < length; key++) { + if (!ObjectUtil.equals(o1[key], o2[key])) { + return false; + } + } + return true; + } + } else { + if (Array.isArray(o2)) { + return false; + } + keySet = Object.create(null); + + for (key in o1) { + if (o1.hasOwnProperty(key)) { + if (!ObjectUtil.equals(o1[key], o2[key])) { + return false; + } + keySet[key] = true; + } + } + + for (key in o2) { + if (!(key in keySet) && typeof o2[key] !== 'undefined') { + return false; + } + } + return true; + } + } + return false; + } +} diff --git a/projects/ucap-webmessenger-core/src/public-api.ts b/projects/ucap-webmessenger-core/src/public-api.ts index e8a3a32b..7c245026 100644 --- a/projects/ucap-webmessenger-core/src/public-api.ts +++ b/projects/ucap-webmessenger-core/src/public-api.ts @@ -22,6 +22,7 @@ export * from './lib/types/video-conference-type.type'; export * from './lib/utils/file.util'; export * from './lib/utils/mime.util'; +export * from './lib/utils/object.util'; export * from './lib/utils/sticker.util'; export * from './lib/utils/string.util'; diff --git a/projects/ucap-webmessenger-ui-organization/src/lib/pipes/translate.pipe.ts b/projects/ucap-webmessenger-ui-organization/src/lib/pipes/translate.pipe.ts new file mode 100644 index 00000000..52c06ec2 --- /dev/null +++ b/projects/ucap-webmessenger-ui-organization/src/lib/pipes/translate.pipe.ts @@ -0,0 +1,164 @@ +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(); + } +}