Skip to content

Commit 7b72914

Browse files
committed
Simplified Isolation: Using a separate store object instead of duplicating variables locally and using if to distinguish between both.
1 parent 4ac0072 commit 7b72914

File tree

2 files changed

+146
-41
lines changed

2 files changed

+146
-41
lines changed

projects/ngx-translate/src/lib/translate.service.spec.ts

+125-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {fakeAsync, TestBed, tick} from "@angular/core/testing";
2-
import {Observable, of, timer, zip, defer} from "rxjs";
2+
import {Observable, of, timer, zip, defer, EMPTY} from "rxjs";
33
import {take, toArray, first, map} from "rxjs/operators";
44
import {
55
LangChangeEvent,
66
TranslateLoader,
77
TranslateService,
8-
TranslationChangeEvent, TranslationObject, Translation, provideTranslateService
8+
TranslationChangeEvent, TranslationObject, Translation, provideTranslateService, TranslatePipe, TranslateModule
99
} from "../public-api";
10+
import {Component} from "@angular/core";
11+
import {Router, RouterOutlet} from "@angular/router";
1012

1113

1214
let translations: TranslationObject = {"TEST": "This is a test"};
@@ -1039,6 +1041,126 @@ describe("TranslateService", () =>
10391041
expect(translate.getBrowserCultureLang()).toBeUndefined();
10401042
});
10411043
});
1044+
});
10421045

10431046

1044-
});
1047+
describe('TranslateService (isolate)', () => {
1048+
const translationsRoot = {
1049+
en: {test : "en-root"},
1050+
de: {test : "de-root"}
1051+
}
1052+
1053+
const translationsChild = {
1054+
en: {test: "en-child"},
1055+
de: {test : "de-child"}
1056+
}
1057+
1058+
class StaticTranslateLoader implements TranslateLoader {
1059+
constructor(private translations: Record<string, unknown>) {
1060+
}
1061+
1062+
getTranslation(lang: string) {
1063+
const translations = this.translations[lang];
1064+
if (translations) {
1065+
return of(translations)
1066+
} else {
1067+
return EMPTY;
1068+
}
1069+
}
1070+
}
1071+
1072+
@Component({
1073+
standalone: true,
1074+
selector: "lib-isolated-child",
1075+
template: `
1076+
<div class="isolated-child">{{ 'test' | translate }}</div>
1077+
`,
1078+
imports: [
1079+
TranslatePipe
1080+
],
1081+
providers: [
1082+
TranslateModule.forChild({
1083+
isolate: true,
1084+
loader: {
1085+
provide: TranslateLoader,
1086+
useFactory: () => new StaticTranslateLoader(translationsChild),
1087+
},
1088+
}).providers!
1089+
]
1090+
})
1091+
class IsolatedChildComponent
1092+
{
1093+
constructor(private translate:TranslateService)
1094+
{
1095+
translate.use("de");
1096+
}
1097+
}
1098+
1099+
@Component({
1100+
standalone: true,
1101+
selector: "lib-shared-child",
1102+
template: `
1103+
<div class="shared-child">{{ 'test' | translate }}</div>
1104+
`,
1105+
imports: [
1106+
TranslatePipe
1107+
],
1108+
providers: [
1109+
TranslateModule.forChild({}).providers!
1110+
]
1111+
})
1112+
class SharedChildComponent
1113+
{
1114+
}
1115+
1116+
@Component({
1117+
standalone: true,
1118+
imports: [RouterOutlet, IsolatedChildComponent, SharedChildComponent, TranslatePipe],
1119+
selector: "lib-test",
1120+
template: `
1121+
<div class="root">{{ 'test' | translate }}</div>
1122+
<lib-isolated-child/>
1123+
<lib-shared-child/>
1124+
`
1125+
})
1126+
class AppTestComponent {
1127+
constructor(private translate:TranslateService)
1128+
{
1129+
translate.use("en");
1130+
}
1131+
}
1132+
1133+
beforeEach(() => {
1134+
TestBed.configureTestingModule({
1135+
providers: [
1136+
provideTranslateService({
1137+
extend: true,
1138+
loader: {
1139+
provide: TranslateLoader,
1140+
useFactory: () => new StaticTranslateLoader(translationsRoot)
1141+
}
1142+
}),
1143+
]
1144+
}).compileComponents();
1145+
})
1146+
1147+
it('switches root and child component independently', async () => {
1148+
const fixture = TestBed.createComponent(AppTestComponent);
1149+
1150+
const app = fixture.nativeElement
1151+
1152+
fixture.detectChanges();
1153+
1154+
expect(app.querySelector("div.root").textContent).toEqual("en-root");
1155+
expect(app.querySelector("div.isolated-child").textContent).toEqual("de-child");
1156+
expect(app.querySelector("div.shared-child").textContent).toEqual("en-root");
1157+
1158+
// switch root
1159+
TestBed.inject(TranslateService).use("de");
1160+
fixture.detectChanges();
1161+
1162+
expect(app.querySelector("div.root").textContent).toEqual("de-root");
1163+
expect(app.querySelector("div.isolated-child").textContent).toEqual("de-child");
1164+
expect(app.querySelector("div.shared-child").textContent).toEqual("de-root");
1165+
})
1166+
})

projects/ngx-translate/src/lib/translate.service.ts

+21-38
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,6 @@ const makeObservable = <T>(value: T | Observable<T>): Observable<T> => {
9191
export class TranslateService {
9292
private loadingTranslations!: Observable<InterpolatableTranslationObject>;
9393
private pending = false;
94-
private _onTranslationChange: EventEmitter<TranslationChangeEvent> = new EventEmitter<TranslationChangeEvent>();
95-
private _onLangChange: EventEmitter<LangChangeEvent> = new EventEmitter<LangChangeEvent>();
96-
private _onDefaultLangChange: EventEmitter<DefaultLangChangeEvent> = new EventEmitter<DefaultLangChangeEvent>();
97-
private _defaultLang!: string;
98-
private _currentLang!: string;
99-
private _langs: string[] = [];
100-
private _translations: Record<string, InterpolatableTranslationObject> = {};
10194
private _translationRequests: Record<string, Observable<TranslationObject>> = {};
10295
private lastUseLanguage: string|null = null;
10396

@@ -109,7 +102,7 @@ export class TranslateService {
109102
* });
110103
*/
111104
get onTranslationChange(): EventEmitter<TranslationChangeEvent> {
112-
return this.isolate ? this._onTranslationChange : this.store.onTranslationChange;
105+
return this.store.onTranslationChange;
113106
}
114107

115108
/**
@@ -119,7 +112,7 @@ export class TranslateService {
119112
* });
120113
*/
121114
get onLangChange(): EventEmitter<LangChangeEvent> {
122-
return this.isolate ? this._onLangChange : this.store.onLangChange;
115+
return this.store.onLangChange;
123116
}
124117

125118
/**
@@ -129,67 +122,51 @@ export class TranslateService {
129122
* });
130123
*/
131124
get onDefaultLangChange() {
132-
return this.isolate ? this._onDefaultLangChange : this.store.onDefaultLangChange;
125+
return this.store.onDefaultLangChange;
133126
}
134127

135128
/**
136129
* The default lang to fallback when translations are missing on the current lang
137130
*/
138131
get defaultLang(): string {
139-
return this.isolate ? this._defaultLang : this.store.defaultLang;
132+
return this.store.defaultLang;
140133
}
141134

142135
set defaultLang(defaultLang: string) {
143-
if (this.isolate) {
144-
this._defaultLang = defaultLang;
145-
} else {
146-
this.store.defaultLang = defaultLang;
147-
}
136+
this.store.defaultLang = defaultLang;
148137
}
149138

150139
/**
151140
* The lang currently used
152141
*/
153142
get currentLang(): string {
154-
return this.isolate ? this._currentLang : this.store.currentLang;
143+
return this.store.currentLang;
155144
}
156145

157146
set currentLang(currentLang: string) {
158-
if (this.isolate) {
159-
this._currentLang = currentLang;
160-
} else {
161-
this.store.currentLang = currentLang;
162-
}
147+
this.store.currentLang = currentLang;
163148
}
164149

165150
/**
166151
* an array of langs
167152
*/
168153
get langs(): string[] {
169-
return this.isolate ? this._langs : this.store.langs;
154+
return this.store.langs;
170155
}
171156

172157
set langs(langs: string[]) {
173-
if (this.isolate) {
174-
this._langs = langs;
175-
} else {
176-
this.store.langs = langs;
177-
}
158+
this.store.langs = langs;
178159
}
179160

180161
/**
181162
* a list of translations per lang
182163
*/
183164
get translations(): Record<string, InterpolatableTranslationObject> {
184-
return this.isolate ? this._translations : this.store.translations;
165+
return this.store.translations;
185166
}
186167

187168
set translations(translations: Record<string, InterpolatableTranslationObject>) {
188-
if (this.isolate) {
189-
this._translations = translations;
190-
} else {
191-
this.store.translations = translations;
192-
}
169+
this.store.translations = translations;
193170
}
194171

195172
/**
@@ -210,10 +187,16 @@ export class TranslateService {
210187
public parser: TranslateParser,
211188
public missingTranslationHandler: MissingTranslationHandler,
212189
@Inject(USE_DEFAULT_LANG) private useDefaultLang = true,
213-
@Inject(ISOALTE_TRANSLATE_SERVICE) private isolate = false,
190+
@Inject(ISOALTE_TRANSLATE_SERVICE) isolate = false,
214191
@Inject(USE_EXTEND) private extend = false,
215-
@Inject(DEFAULT_LANGUAGE) defaultLanguage: string) {
216-
/** set the default language from configuration */
192+
@Inject(DEFAULT_LANGUAGE) defaultLanguage: string
193+
)
194+
{
195+
if(isolate)
196+
{
197+
this.store = new TranslateStore();
198+
}
199+
217200
if (defaultLanguage) {
218201
this.setDefaultLang(defaultLanguage);
219202
}
@@ -361,7 +344,7 @@ export class TranslateService {
361344
this.loadingTranslations
362345
.subscribe({
363346
next: (res: InterpolatableTranslationObject) => {
364-
this.translations[lang] = this.extend && this.translations[lang] ? { ...res, ...this.translations[lang] } : res;
347+
this.translations[lang] = (this.extend && this.translations[lang]) ? { ...res, ...this.translations[lang] } : res;
365348
this.updateLangs();
366349
this.pending = false;
367350
},

0 commit comments

Comments
 (0)