Skip to content

Commit 2088195

Browse files
committed
feat(TranslationService): getting translations for default lang when it's set
Fixes #332 Fixes #336 BREAKING CHANGE: we will now fetch the translations for the default lang when it is set (if they are not already available). Also the default lang is now automatically set to the first lang that receives translations (if it is still undefined at that time). Setting the default lang will override this default behavior, so this will probably not break anything for you, but if you set the translations for the default lang first then you don't even have to call `setDefaultLang` anymore.
1 parent 38e0cd9 commit 2088195

File tree

3 files changed

+61
-31
lines changed

3 files changed

+61
-31
lines changed

src/translate.directive.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {Directive, ElementRef, AfterViewChecked, Input, OnDestroy} from '@angula
22
import {Subscription} from 'rxjs';
33
import {isDefined} from './util';
44
import {TranslateService, LangChangeEvent} from './translate.service';
5+
import {TranslationChangeEvent} from "./translate.service";
6+
import {DefaultLangChangeEvent} from "./translate.service";
57

68
@Directive({
79
selector: '[translate],[ng2-translate]'
@@ -11,6 +13,7 @@ export class TranslateDirective implements AfterViewChecked, OnDestroy {
1113
lastParams: any;
1214
onLangChangeSub: Subscription;
1315
onDefaultLangChangeSub: Subscription;
16+
onTranslationChangeSub: Subscription;
1417

1518
@Input() set translate(key: string) {
1619
if(key) {
@@ -22,17 +25,26 @@ export class TranslateDirective implements AfterViewChecked, OnDestroy {
2225
@Input() translateParams: any;
2326

2427
constructor(private translateService: TranslateService, private element: ElementRef) {
28+
// subscribe to onTranslationChange event, in case the translations of the current lang change
29+
if(!this.onTranslationChangeSub) {
30+
this.onTranslationChangeSub = this.translateService.onTranslationChange.subscribe((event: TranslationChangeEvent) => {
31+
if(event.lang === this.translateService.currentLang) {
32+
this.checkNodes(true, event.translations);
33+
}
34+
});
35+
}
36+
2537
// subscribe to onLangChange event, in case the language changes
2638
if(!this.onLangChangeSub) {
2739
this.onLangChangeSub = this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
28-
this.checkNodes(event.translations);
40+
this.checkNodes(true, event.translations);
2941
});
3042
}
3143

3244
// subscribe to onDefaultLangChange event, in case the default language changes
3345
if(!this.onDefaultLangChangeSub) {
34-
this.onDefaultLangChangeSub = this.translateService.onDefaultLangChange.subscribe(() => {
35-
this.checkNodes();
46+
this.onDefaultLangChangeSub = this.translateService.onDefaultLangChange.subscribe((event: DefaultLangChangeEvent) => {
47+
this.checkNodes(true);
3648
});
3749
}
3850
}
@@ -41,7 +53,7 @@ export class TranslateDirective implements AfterViewChecked, OnDestroy {
4153
this.checkNodes();
4254
}
4355

44-
checkNodes(translations?: any) {
56+
checkNodes(forceUpdate = false, translations?: any) {
4557
let nodes: NodeList = this.element.nativeElement.childNodes;
4658
for(let i = 0; i < nodes.length; ++i) {
4759
let node: any = nodes[i];
@@ -57,7 +69,7 @@ export class TranslateDirective implements AfterViewChecked, OnDestroy {
5769
key = content;
5870
// the content was changed from the user, we'll use it as a reference if needed
5971
node.originalContent = node.textContent;
60-
} else if(node.originalContent && isDefined(translations)) { // the content seems ok, but the lang has changed
72+
} else if(node.originalContent && forceUpdate) { // the content seems ok, but the lang has changed
6173
node.lastKey = null;
6274
// the current content is the translation, not the key, use the last real content as key
6375
key = node.originalContent.trim();
@@ -111,5 +123,9 @@ export class TranslateDirective implements AfterViewChecked, OnDestroy {
111123
if(this.onDefaultLangChangeSub) {
112124
this.onDefaultLangChangeSub.unsubscribe();
113125
}
126+
127+
if(this.onTranslationChangeSub) {
128+
this.onTranslationChangeSub.unsubscribe();
129+
}
114130
}
115131
}

src/translate.service.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "rxjs/add/operator/share";
77
import "rxjs/add/operator/map";
88
import "rxjs/add/operator/merge";
99
import "rxjs/add/operator/toArray";
10+
import "rxjs/add/operator/take";
1011

1112
import {TranslateParser} from "./translate.parser";
1213
import {isDefined} from "./util";
@@ -129,6 +130,7 @@ export class TranslateService {
129130
/**
130131
*
131132
* @param currentLoader An instance of the loader currently used
133+
* @param parser An instance of the parser currently used
132134
* @param missingTranslationHandler A handler for missing translations.
133135
*/
134136
constructor(
@@ -142,6 +144,10 @@ export class TranslateService {
142144
* @param lang
143145
*/
144146
public setDefaultLang(lang: string): void {
147+
if(lang === this.defaultLang) {
148+
return;
149+
}
150+
145151
let pending: Observable<any> = this.retrieveTranslations(lang);
146152

147153
if(typeof pending !== "undefined") {
@@ -150,10 +156,10 @@ export class TranslateService {
150156
this.defaultLang = lang;
151157
}
152158

153-
pending.subscribe((res: any) => {
154-
this.changeDefaultLang(lang);
155-
}, (err: any) => {
156-
});
159+
pending.take(1)
160+
.subscribe((res: any) => {
161+
this.changeDefaultLang(lang);
162+
});
157163
} else { // we already have this language
158164
this.changeDefaultLang(lang);
159165
}
@@ -180,10 +186,11 @@ export class TranslateService {
180186
if(!this.currentLang) {
181187
this.currentLang = lang;
182188
}
183-
pending.subscribe((res: any) => {
184-
this.changeLang(lang);
185-
}, (err: any) => {
186-
});
189+
190+
pending.take(1)
191+
.subscribe((res: any) => {
192+
this.changeLang(lang);
193+
});
187194

188195
return pending;
189196
} else { // we have this language, return an Observable
@@ -200,11 +207,12 @@ export class TranslateService {
200207
*/
201208
private retrieveTranslations(lang: string): Observable<any> {
202209
let pending: Observable<any>;
203-
// check if this language is available
210+
211+
// if this language is unavailable, ask for it
204212
if(typeof this.translations[lang] === "undefined") {
205-
// not available, ask for it
206213
pending = this.getTranslation(lang);
207214
}
215+
208216
return pending;
209217
}
210218

@@ -215,13 +223,15 @@ export class TranslateService {
215223
*/
216224
public getTranslation(lang: string): Observable<any> {
217225
this.pending = this.currentLoader.getTranslation(lang).share();
218-
this.pending.subscribe((res: Object) => {
219-
this.translations[lang] = res;
220-
this.updateLangs();
221-
this.pending = undefined;
222-
}, (err: any) => {
223-
this.pending = undefined;
224-
});
226+
227+
this.pending.take(1)
228+
.subscribe((res: Object) => {
229+
this.translations[lang] = res;
230+
this.updateLangs();
231+
this.pending = undefined;
232+
}, (err: any) => {
233+
this.pending = undefined;
234+
});
225235

226236
return this.pending;
227237
}
@@ -235,11 +245,11 @@ export class TranslateService {
235245
public setTranslation(lang: string, translations: Object, shouldMerge: boolean = false): void {
236246
if(shouldMerge && this.translations[lang]) {
237247
Object.assign(this.translations[lang], translations);
238-
this.onTranslationChange.emit({translations: this.translations[lang], lang: lang});
239248
} else {
240249
this.translations[lang] = translations;
241250
}
242251
this.updateLangs();
252+
this.onTranslationChange.emit({lang: lang, translations: this.translations[lang]});
243253
}
244254

245255
/**
@@ -317,15 +327,15 @@ export class TranslateService {
317327
res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams);
318328
}
319329

320-
if (!res && this.missingTranslationHandler) {
321-
let params: MissingTranslationHandlerParams = { key, translateService: this };
322-
if (typeof interpolateParams !== 'undefined') {
330+
if(!res && this.missingTranslationHandler) {
331+
let params: MissingTranslationHandlerParams = {key, translateService: this};
332+
if(typeof interpolateParams !== 'undefined') {
323333
params.interpolateParams = interpolateParams;
324334
}
325335
res = this.missingTranslationHandler.handle(params);
326336
}
327337

328-
return res !== undefined ? res : key;
338+
return typeof res !== "undefined" ? res : key;
329339
}
330340

331341
/**
@@ -403,7 +413,7 @@ export class TranslateService {
403413
public set(key: string, value: string, lang: string = this.currentLang): void {
404414
this.translations[lang][key] = value;
405415
this.updateLangs();
406-
this.onTranslationChange.emit({translations: {[key]: value}, lang: lang});
416+
this.onTranslationChange.emit({lang: lang, translations: this.translations[lang]});
407417
}
408418

409419
/**
@@ -413,6 +423,11 @@ export class TranslateService {
413423
private changeLang(lang: string): void {
414424
this.currentLang = lang;
415425
this.onLangChange.emit({lang: lang, translations: this.translations[lang]});
426+
427+
// if there is no default lang, use the one that we just set
428+
if(!this.defaultLang) {
429+
this.changeDefaultLang(lang);
430+
}
416431
}
417432

418433
/**
@@ -472,7 +487,7 @@ export class TranslateService {
472487
* @returns string
473488
*/
474489
public getBrowserCultureLang(): string {
475-
if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {
490+
if(typeof window === 'undefined' || typeof window.navigator === 'undefined') {
476491
return undefined;
477492
}
478493

tests/translate.directive.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,11 @@ describe('TranslateDirective', () => {
117117

118118
// Test (temporarily) disabled as the directive tests manipulate the DOM manually which breaks this test.
119119
// https://github.com/ocombe/ng2-translate/pull/336
120-
xit('should update the DOM when the default lang changes', () => {
120+
it('should update the DOM when the default lang changes', () => {
121121
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('TEST');
122122

123123
translate.setTranslation('en', {"TEST": "This is a test"});
124124
translate.setTranslation('fr', {"TEST": "C'est un test"});
125-
126125
translate.setDefaultLang('en');
127126
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('This is a test');
128127

0 commit comments

Comments
 (0)