@ngx-translate/core
Version:
165 lines (147 loc) • 5.87 kB
text/typescript
import {AfterViewChecked, ChangeDetectorRef, Directive, ElementRef, Input, OnDestroy} from '@angular/core';
import {Subscription, isObservable} from 'rxjs';
import {DefaultLangChangeEvent, LangChangeEvent, TranslateService, TranslationChangeEvent} from './translate.service';
import {equals, isDefined} from './util';
export class TranslateDirective implements AfterViewChecked, OnDestroy {
key!: string;
lastParams: any;
currentParams: any;
onLangChangeSub!: Subscription;
onDefaultLangChangeSub!: Subscription;
onTranslationChangeSub!: Subscription;
set translate(key: string) {
if (key) {
this.key = key;
this.checkNodes();
}
}
set translateParams(params: any) {
if (!equals(this.currentParams, params)) {
this.currentParams = params;
this.checkNodes(true);
}
}
constructor(private translateService: TranslateService, private element: ElementRef, private _ref: ChangeDetectorRef) {
// subscribe to onTranslationChange event, in case the translations of the current lang change
if (!this.onTranslationChangeSub) {
this.onTranslationChangeSub = this.translateService.onTranslationChange.subscribe((event: TranslationChangeEvent) => {
if (event.lang === this.translateService.currentLang) {
this.checkNodes(true, event.translations);
}
});
}
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChangeSub) {
this.onLangChangeSub = this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
this.checkNodes(true, event.translations);
});
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChangeSub) {
this.onDefaultLangChangeSub = this.translateService.onDefaultLangChange.subscribe((event: DefaultLangChangeEvent) => {
this.checkNodes(true);
});
}
}
ngAfterViewChecked() {
this.checkNodes();
}
checkNodes(forceUpdate = false, translations?: any) {
let nodes: NodeList = this.element.nativeElement.childNodes;
// if the element is empty
if (!nodes.length) {
// we add the key as content
this.setContent(this.element.nativeElement, this.key);
nodes = this.element.nativeElement.childNodes;
}
for (let i = 0; i < nodes.length; ++i) {
let node: any = nodes[i];
if (node.nodeType === 3) { // node type 3 is a text node
let key!: string;
if (forceUpdate) {
node.lastKey = null;
}
if(isDefined(node.lookupKey)) {
key = node.lookupKey;
} else if (this.key) {
key = this.key;
} else {
let content = this.getContent(node);
let trimmedContent = content.trim();
if (trimmedContent.length) {
node.lookupKey = trimmedContent;
// we want to use the content as a key, not the translation value
if (content !== node.currentValue) {
key = trimmedContent;
// the content was changed from the user, we'll use it as a reference if needed
node.originalContent = content || node.originalContent;
} else if (node.originalContent) { // the content seems ok, but the lang has changed
// the current content is the translation, not the key, use the last real content as key
key = node.originalContent.trim();
} else if (content !== node.currentValue) {
// we want to use the content as a key, not the translation value
key = trimmedContent;
// the content was changed from the user, we'll use it as a reference if needed
node.originalContent = content || node.originalContent;
}
}
}
this.updateValue(key, node, translations);
}
}
}
updateValue(key: string, node: any, translations: any) {
if (key) {
if (node.lastKey === key && this.lastParams === this.currentParams) {
return;
}
this.lastParams = this.currentParams;
let onTranslation = (res: unknown) => {
if (res !== key) {
node.lastKey = key;
}
if (!node.originalContent) {
node.originalContent = this.getContent(node);
}
node.currentValue = isDefined(res) ? res : (node.originalContent || key);
// we replace in the original content to preserve spaces that we might have trimmed
this.setContent(node, this.key ? node.currentValue : node.originalContent.replace(key, node.currentValue));
this._ref.markForCheck();
};
if (isDefined(translations)) {
let res = this.translateService.getParsedResult(translations, key, this.currentParams);
if (isObservable(res)) {
res.subscribe({next: onTranslation});
} else {
onTranslation(res);
}
} else {
this.translateService.get(key, this.currentParams).subscribe(onTranslation);
}
}
}
getContent(node: any): string {
return isDefined(node.textContent) ? node.textContent : node.data;
}
setContent(node: any, content: string): void {
if (isDefined(node.textContent)) {
node.textContent = content;
} else {
node.data = content;
}
}
ngOnDestroy() {
if (this.onLangChangeSub) {
this.onLangChangeSub.unsubscribe();
}
if (this.onDefaultLangChangeSub) {
this.onDefaultLangChangeSub.unsubscribe();
}
if (this.onTranslationChangeSub) {
this.onTranslationChangeSub.unsubscribe();
}
}
}