Skip to content

Commit

Permalink
Simplified Isolation: Using a separate store object instead of duplic…
Browse files Browse the repository at this point in the history
…ating variables locally and using if to distinguish between both.
  • Loading branch information
CodeAndWeb committed Nov 13, 2024
1 parent 4ac0072 commit 7b72914
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 41 deletions.
128 changes: 125 additions & 3 deletions projects/ngx-translate/src/lib/translate.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {fakeAsync, TestBed, tick} from "@angular/core/testing";
import {Observable, of, timer, zip, defer} from "rxjs";
import {Observable, of, timer, zip, defer, EMPTY} from "rxjs";
import {take, toArray, first, map} from "rxjs/operators";
import {
LangChangeEvent,
TranslateLoader,
TranslateService,
TranslationChangeEvent, TranslationObject, Translation, provideTranslateService
TranslationChangeEvent, TranslationObject, Translation, provideTranslateService, TranslatePipe, TranslateModule
} from "../public-api";
import {Component} from "@angular/core";
import {Router, RouterOutlet} from "@angular/router";


let translations: TranslationObject = {"TEST": "This is a test"};
Expand Down Expand Up @@ -1039,6 +1041,126 @@ describe("TranslateService", () =>
expect(translate.getBrowserCultureLang()).toBeUndefined();
});
});
});


});
describe('TranslateService (isolate)', () => {
const translationsRoot = {
en: {test : "en-root"},
de: {test : "de-root"}
}

const translationsChild = {
en: {test: "en-child"},
de: {test : "de-child"}
}

class StaticTranslateLoader implements TranslateLoader {
constructor(private translations: Record<string, unknown>) {
}

getTranslation(lang: string) {
const translations = this.translations[lang];
if (translations) {
return of(translations)
} else {
return EMPTY;
}
}
}

@Component({
standalone: true,
selector: "lib-isolated-child",
template: `
<div class="isolated-child">{{ 'test' | translate }}</div>
`,
imports: [
TranslatePipe
],
providers: [
TranslateModule.forChild({
isolate: true,
loader: {
provide: TranslateLoader,
useFactory: () => new StaticTranslateLoader(translationsChild),
},
}).providers!
]
})
class IsolatedChildComponent
{
constructor(private translate:TranslateService)
{
translate.use("de");
}
}

@Component({
standalone: true,
selector: "lib-shared-child",
template: `
<div class="shared-child">{{ 'test' | translate }}</div>
`,
imports: [
TranslatePipe
],
providers: [
TranslateModule.forChild({}).providers!
]
})
class SharedChildComponent
{
}

@Component({
standalone: true,
imports: [RouterOutlet, IsolatedChildComponent, SharedChildComponent, TranslatePipe],
selector: "lib-test",
template: `
<div class="root">{{ 'test' | translate }}</div>
<lib-isolated-child/>
<lib-shared-child/>
`
})
class AppTestComponent {
constructor(private translate:TranslateService)
{
translate.use("en");
}
}

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideTranslateService({
extend: true,
loader: {
provide: TranslateLoader,
useFactory: () => new StaticTranslateLoader(translationsRoot)
}
}),
]
}).compileComponents();
})

it('switches root and child component independently', async () => {
const fixture = TestBed.createComponent(AppTestComponent);

const app = fixture.nativeElement

fixture.detectChanges();

expect(app.querySelector("div.root").textContent).toEqual("en-root");
expect(app.querySelector("div.isolated-child").textContent).toEqual("de-child");
expect(app.querySelector("div.shared-child").textContent).toEqual("en-root");

// switch root
TestBed.inject(TranslateService).use("de");
fixture.detectChanges();

expect(app.querySelector("div.root").textContent).toEqual("de-root");
expect(app.querySelector("div.isolated-child").textContent).toEqual("de-child");
expect(app.querySelector("div.shared-child").textContent).toEqual("de-root");
})
})
59 changes: 21 additions & 38 deletions projects/ngx-translate/src/lib/translate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,6 @@ const makeObservable = <T>(value: T | Observable<T>): Observable<T> => {
export class TranslateService {
private loadingTranslations!: Observable<InterpolatableTranslationObject>;
private pending = false;
private _onTranslationChange: EventEmitter<TranslationChangeEvent> = new EventEmitter<TranslationChangeEvent>();
private _onLangChange: EventEmitter<LangChangeEvent> = new EventEmitter<LangChangeEvent>();
private _onDefaultLangChange: EventEmitter<DefaultLangChangeEvent> = new EventEmitter<DefaultLangChangeEvent>();
private _defaultLang!: string;
private _currentLang!: string;
private _langs: string[] = [];
private _translations: Record<string, InterpolatableTranslationObject> = {};
private _translationRequests: Record<string, Observable<TranslationObject>> = {};
private lastUseLanguage: string|null = null;

Expand All @@ -109,7 +102,7 @@ export class TranslateService {
* });
*/
get onTranslationChange(): EventEmitter<TranslationChangeEvent> {
return this.isolate ? this._onTranslationChange : this.store.onTranslationChange;
return this.store.onTranslationChange;
}

/**
Expand All @@ -119,7 +112,7 @@ export class TranslateService {
* });
*/
get onLangChange(): EventEmitter<LangChangeEvent> {
return this.isolate ? this._onLangChange : this.store.onLangChange;
return this.store.onLangChange;
}

/**
Expand All @@ -129,67 +122,51 @@ export class TranslateService {
* });
*/
get onDefaultLangChange() {
return this.isolate ? this._onDefaultLangChange : this.store.onDefaultLangChange;
return this.store.onDefaultLangChange;
}

/**
* The default lang to fallback when translations are missing on the current lang
*/
get defaultLang(): string {
return this.isolate ? this._defaultLang : this.store.defaultLang;
return this.store.defaultLang;
}

set defaultLang(defaultLang: string) {
if (this.isolate) {
this._defaultLang = defaultLang;
} else {
this.store.defaultLang = defaultLang;
}
this.store.defaultLang = defaultLang;
}

/**
* The lang currently used
*/
get currentLang(): string {
return this.isolate ? this._currentLang : this.store.currentLang;
return this.store.currentLang;
}

set currentLang(currentLang: string) {
if (this.isolate) {
this._currentLang = currentLang;
} else {
this.store.currentLang = currentLang;
}
this.store.currentLang = currentLang;
}

/**
* an array of langs
*/
get langs(): string[] {
return this.isolate ? this._langs : this.store.langs;
return this.store.langs;
}

set langs(langs: string[]) {
if (this.isolate) {
this._langs = langs;
} else {
this.store.langs = langs;
}
this.store.langs = langs;
}

/**
* a list of translations per lang
*/
get translations(): Record<string, InterpolatableTranslationObject> {
return this.isolate ? this._translations : this.store.translations;
return this.store.translations;
}

set translations(translations: Record<string, InterpolatableTranslationObject>) {
if (this.isolate) {
this._translations = translations;
} else {
this.store.translations = translations;
}
this.store.translations = translations;
}

/**
Expand All @@ -210,10 +187,16 @@ export class TranslateService {
public parser: TranslateParser,
public missingTranslationHandler: MissingTranslationHandler,
@Inject(USE_DEFAULT_LANG) private useDefaultLang = true,
@Inject(ISOALTE_TRANSLATE_SERVICE) private isolate = false,
@Inject(ISOALTE_TRANSLATE_SERVICE) isolate = false,
@Inject(USE_EXTEND) private extend = false,
@Inject(DEFAULT_LANGUAGE) defaultLanguage: string) {
/** set the default language from configuration */
@Inject(DEFAULT_LANGUAGE) defaultLanguage: string
)
{
if(isolate)
{
this.store = new TranslateStore();
}

if (defaultLanguage) {
this.setDefaultLang(defaultLanguage);
}
Expand Down Expand Up @@ -361,7 +344,7 @@ export class TranslateService {
this.loadingTranslations
.subscribe({
next: (res: InterpolatableTranslationObject) => {
this.translations[lang] = this.extend && this.translations[lang] ? { ...res, ...this.translations[lang] } : res;
this.translations[lang] = (this.extend && this.translations[lang]) ? { ...res, ...this.translations[lang] } : res;
this.updateLangs();
this.pending = false;
},
Expand Down

0 comments on commit 7b72914

Please sign in to comment.