UNPKG

4.89 kBPlain TextView Raw
1import {ChangeDetectorRef, EventEmitter, Injectable, OnDestroy, Pipe, PipeTransform} from '@angular/core';
2import {isObservable} from 'rxjs';
3import {DefaultLangChangeEvent, LangChangeEvent, TranslateService, TranslationChangeEvent} from './translate.service';
4import {equals, isDefined} from './util';
5import { Subscription } from 'rxjs';
6
7@Injectable()
8@Pipe({
9 name: 'translate',
10 pure: false // required to update the value when the promise is resolved
11})
12export class TranslatePipe implements PipeTransform, OnDestroy {
13 value: string = '';
14 lastKey: string | null = null;
15 lastParams: any[] = [];
16 onTranslationChange: Subscription | undefined;
17 onLangChange: Subscription | undefined;
18 onDefaultLangChange: Subscription | undefined;
19
20 constructor(private translate: TranslateService, private _ref: ChangeDetectorRef) {
21 }
22
23 updateValue(key: string, interpolateParams?: Object, translations?: any): void {
24 let onTranslation = (res: string) => {
25 this.value = res !== undefined ? res : key;
26 this.lastKey = key;
27 this._ref.markForCheck();
28 };
29 if (translations) {
30 let res = this.translate.getParsedResult(translations, key, interpolateParams);
31 if (isObservable(res.subscribe)) {
32 res.subscribe(onTranslation);
33 } else {
34 onTranslation(res);
35 }
36 }
37 this.translate.get(key, interpolateParams).subscribe(onTranslation);
38 }
39
40 transform(query: string, ...args: any[]): any {
41 if (!query || !query.length) {
42 return query;
43 }
44
45 // if we ask another time for the same key, return the last value
46 if (equals(query, this.lastKey) && equals(args, this.lastParams)) {
47 return this.value;
48 }
49
50 let interpolateParams: Object | undefined = undefined;
51 if (isDefined(args[0]) && args.length) {
52 if (typeof args[0] === 'string' && args[0].length) {
53 // we accept objects written in the template such as {n:1}, {'n':1}, {n:'v'}
54 // which is why we might need to change it to real JSON objects such as {"n":1} or {"n":"v"}
55 let validArgs: string = args[0]
56 .replace(/(\')?([a-zA-Z0-9_]+)(\')?(\s)?:/g, '"$2":')
57 .replace(/:(\s)?(\')(.*?)(\')/g, ':"$3"');
58 try {
59 interpolateParams = JSON.parse(validArgs);
60 } catch (e) {
61 throw new SyntaxError(`Wrong parameter in TranslatePipe. Expected a valid Object, received: ${args[0]}`);
62 }
63 } else if (typeof args[0] === 'object' && !Array.isArray(args[0])) {
64 interpolateParams = args[0];
65 }
66 }
67
68 // store the query, in case it changes
69 this.lastKey = query;
70
71 // store the params, in case they change
72 this.lastParams = args;
73
74 // set the value
75 this.updateValue(query, interpolateParams);
76
77 // if there is a subscription to onLangChange, clean it
78 this._dispose();
79
80 // subscribe to onTranslationChange event, in case the translations change
81 if (!this.onTranslationChange) {
82 this.onTranslationChange = this.translate.onTranslationChange.subscribe((event: TranslationChangeEvent) => {
83 if (this.lastKey && event.lang === this.translate.currentLang) {
84 this.lastKey = null;
85 this.updateValue(query, interpolateParams, event.translations);
86 }
87 });
88 }
89
90 // subscribe to onLangChange event, in case the language changes
91 if (!this.onLangChange) {
92 this.onLangChange = this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
93 if (this.lastKey) {
94 this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
95 this.updateValue(query, interpolateParams, event.translations);
96 }
97 });
98 }
99
100 // subscribe to onDefaultLangChange event, in case the default language changes
101 if (!this.onDefaultLangChange) {
102 this.onDefaultLangChange = this.translate.onDefaultLangChange.subscribe(() => {
103 if (this.lastKey) {
104 this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
105 this.updateValue(query, interpolateParams);
106 }
107 });
108 }
109
110 return this.value;
111 }
112
113 /**
114 * Clean any existing subscription to change events
115 */
116 private _dispose(): void {
117 if (typeof this.onTranslationChange !== 'undefined') {
118 this.onTranslationChange.unsubscribe();
119 this.onTranslationChange = undefined;
120 }
121 if (typeof this.onLangChange !== 'undefined') {
122 this.onLangChange.unsubscribe();
123 this.onLangChange = undefined;
124 }
125 if (typeof this.onDefaultLangChange !== 'undefined') {
126 this.onDefaultLangChange.unsubscribe();
127 this.onDefaultLangChange = undefined;
128 }
129 }
130
131 ngOnDestroy(): void {
132 this._dispose();
133 }
134}