1 | import {AfterViewChecked, ChangeDetectorRef, Directive, ElementRef, Input, OnDestroy} from '@angular/core';
|
2 | import {Subscription, isObservable} from 'rxjs';
|
3 | import {DefaultLangChangeEvent, LangChangeEvent, TranslateService, TranslationChangeEvent} from './translate.service';
|
4 | import {equals, isDefined} from './util';
|
5 |
|
6 | @Directive({
|
7 | selector: '[translate],[ngx-translate]'
|
8 | })
|
9 | export class TranslateDirective implements AfterViewChecked, OnDestroy {
|
10 | key!: string;
|
11 | lastParams: any;
|
12 | currentParams: any;
|
13 | onLangChangeSub!: Subscription;
|
14 | onDefaultLangChangeSub!: Subscription;
|
15 | onTranslationChangeSub!: Subscription;
|
16 |
|
17 | @Input() set translate(key: string) {
|
18 | if (key) {
|
19 | this.key = key;
|
20 | this.checkNodes();
|
21 | }
|
22 | }
|
23 |
|
24 | @Input() set translateParams(params: any) {
|
25 | if (!equals(this.currentParams, params)) {
|
26 | this.currentParams = params;
|
27 | this.checkNodes(true);
|
28 | }
|
29 | }
|
30 |
|
31 | constructor(private translateService: TranslateService, private element: ElementRef, private _ref: ChangeDetectorRef) {
|
32 |
|
33 | if (!this.onTranslationChangeSub) {
|
34 | this.onTranslationChangeSub = this.translateService.onTranslationChange.subscribe((event: TranslationChangeEvent) => {
|
35 | if (event.lang === this.translateService.currentLang) {
|
36 | this.checkNodes(true, event.translations);
|
37 | }
|
38 | });
|
39 | }
|
40 |
|
41 |
|
42 | if (!this.onLangChangeSub) {
|
43 | this.onLangChangeSub = this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
44 | this.checkNodes(true, event.translations);
|
45 | });
|
46 | }
|
47 |
|
48 |
|
49 | if (!this.onDefaultLangChangeSub) {
|
50 | this.onDefaultLangChangeSub = this.translateService.onDefaultLangChange.subscribe((event: DefaultLangChangeEvent) => {
|
51 | this.checkNodes(true);
|
52 | });
|
53 | }
|
54 | }
|
55 |
|
56 | ngAfterViewChecked() {
|
57 | this.checkNodes();
|
58 | }
|
59 |
|
60 | checkNodes(forceUpdate = false, translations?: any) {
|
61 | let nodes: NodeList = this.element.nativeElement.childNodes;
|
62 |
|
63 | if (!nodes.length) {
|
64 |
|
65 | this.setContent(this.element.nativeElement, this.key);
|
66 | nodes = this.element.nativeElement.childNodes;
|
67 | }
|
68 | for (let i = 0; i < nodes.length; ++i) {
|
69 | let node: any = nodes[i];
|
70 | if (node.nodeType === 3) {
|
71 | let key!: string;
|
72 | if (forceUpdate) {
|
73 | node.lastKey = null;
|
74 | }
|
75 | if(isDefined(node.lookupKey)) {
|
76 | key = node.lookupKey;
|
77 | } else if (this.key) {
|
78 | key = this.key;
|
79 | } else {
|
80 | let content = this.getContent(node);
|
81 | let trimmedContent = content.trim();
|
82 | if (trimmedContent.length) {
|
83 | node.lookupKey = trimmedContent;
|
84 |
|
85 | if (content !== node.currentValue) {
|
86 | key = trimmedContent;
|
87 |
|
88 | node.originalContent = content || node.originalContent;
|
89 | } else if (node.originalContent) {
|
90 |
|
91 | key = node.originalContent.trim();
|
92 | } else if (content !== node.currentValue) {
|
93 |
|
94 | key = trimmedContent;
|
95 |
|
96 | node.originalContent = content || node.originalContent;
|
97 | }
|
98 | }
|
99 | }
|
100 | this.updateValue(key, node, translations);
|
101 | }
|
102 | }
|
103 | }
|
104 |
|
105 | updateValue(key: string, node: any, translations: any) {
|
106 | if (key) {
|
107 | if (node.lastKey === key && this.lastParams === this.currentParams) {
|
108 | return;
|
109 | }
|
110 |
|
111 | this.lastParams = this.currentParams;
|
112 |
|
113 | let onTranslation = (res: unknown) => {
|
114 | if (res !== key) {
|
115 | node.lastKey = key;
|
116 | }
|
117 | if (!node.originalContent) {
|
118 | node.originalContent = this.getContent(node);
|
119 | }
|
120 | node.currentValue = isDefined(res) ? res : (node.originalContent || key);
|
121 |
|
122 | this.setContent(node, this.key ? node.currentValue : node.originalContent.replace(key, node.currentValue));
|
123 | this._ref.markForCheck();
|
124 | };
|
125 |
|
126 | if (isDefined(translations)) {
|
127 | let res = this.translateService.getParsedResult(translations, key, this.currentParams);
|
128 | if (isObservable(res)) {
|
129 | res.subscribe({next: onTranslation});
|
130 | } else {
|
131 | onTranslation(res);
|
132 | }
|
133 | } else {
|
134 | this.translateService.get(key, this.currentParams).subscribe(onTranslation);
|
135 | }
|
136 | }
|
137 | }
|
138 |
|
139 | getContent(node: any): string {
|
140 | return isDefined(node.textContent) ? node.textContent : node.data;
|
141 | }
|
142 |
|
143 | setContent(node: any, content: string): void {
|
144 | if (isDefined(node.textContent)) {
|
145 | node.textContent = content;
|
146 | } else {
|
147 | node.data = content;
|
148 | }
|
149 | }
|
150 |
|
151 | ngOnDestroy() {
|
152 | if (this.onLangChangeSub) {
|
153 | this.onLangChangeSub.unsubscribe();
|
154 | }
|
155 |
|
156 | if (this.onDefaultLangChangeSub) {
|
157 | this.onDefaultLangChangeSub.unsubscribe();
|
158 | }
|
159 |
|
160 | if (this.onTranslationChangeSub) {
|
161 | this.onTranslationChangeSub.unsubscribe();
|
162 | }
|
163 | }
|
164 | }
|