Skip to content

Commit

Permalink
Introducing provideTranslateService() instead of TranslateModule.forR…
Browse files Browse the repository at this point in the history
…oot() for standalone components
  • Loading branch information
CodeAndWeb committed Sep 24, 2024
1 parent 7acc672 commit c5c5798
Show file tree
Hide file tree
Showing 12 changed files with 606 additions and 43 deletions.
19 changes: 9 additions & 10 deletions projects/http-loader/src/lib/http-loader.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {HttpClient, provideHttpClient} from "@angular/common/http";
import {HttpTestingController, provideHttpClientTesting} from "@angular/common/http/testing";
import {TestBed} from "@angular/core/testing";
import {TranslateLoader, TranslateModule, TranslateService, Translation} from "@codeandweb/ngx-translate";
import {TranslateLoader, provideTranslateService, TranslateService, Translation} from "@codeandweb/ngx-translate";
import {TranslateHttpLoader} from "../public-api";

describe('TranslateLoader', () => {
Expand All @@ -10,19 +10,18 @@ describe('TranslateLoader', () => {

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (httpClient: HttpClient) => new TranslateHttpLoader(httpClient),
deps: [HttpClient]
}
})
],
providers: [
TranslateService,
provideHttpClient(),
provideHttpClientTesting(),
provideTranslateService({
loader: {
provide: TranslateLoader,
useFactory: (httpClient: HttpClient) => new TranslateHttpLoader(httpClient),
deps: [HttpClient]
}
}
)
]
});
translate = TestBed.inject(TranslateService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import {TestBed} from "@angular/core/testing";
import {Observable, of} from "rxjs";
import {
MissingTranslationHandler,
MissingTranslationHandlerParams,
MissingTranslationHandlerParams, provideTranslateService,
TranslateLoader,
TranslateModule,
TranslateService, Translation,
TranslationObject
} from "../public-api";
import {Type} from "@angular/core";

let translations: TranslationObject = {"TEST": "This is a test"};
const fakeTranslation: TranslationObject = {"NOT_USED": "not used"};
Expand Down Expand Up @@ -39,16 +39,14 @@ describe('MissingTranslationHandler', () => {
}
}

const prepare = ((handlerClass: typeof MissingTranslationHandler, defaultLang = true) => {
const prepare = ((handlerClass: Type<MissingTranslationHandler>, defaultLang = true) => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
providers: [
provideTranslateService({
loader: {provide: TranslateLoader, useClass: FakeLoader},
missingTranslationHandler: {provide: MissingTranslationHandler, useClass: handlerClass},
useDefaultLang: defaultLang
})
],
providers: [
{provide: MissingTranslationHandler, useClass: handlerClass}
]
});
translate = TestBed.inject(TranslateService);
Expand Down
15 changes: 8 additions & 7 deletions projects/ngx-translate/src/lib/translate.compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
TranslateCompiler,
TranslateFakeCompiler,
TranslateLoader,
TranslateModule,
TranslateService,
TranslationObject, Translation
TranslationObject,
Translation,
provideTranslateService
} from "../public-api";

const translations: TranslationObject = {LOAD: 'This is a test'};
Expand All @@ -25,12 +26,12 @@ describe('TranslateCompiler', () => {
describe('with default TranslateFakeCompiler', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
providers: [
provideTranslateService({
loader: {provide: TranslateLoader, useClass: FakeLoader},
compiler: {provide: TranslateCompiler, useClass: TranslateFakeCompiler}
})
],
]
});
translate = TestBed.inject(TranslateService);

Expand Down Expand Up @@ -78,8 +79,8 @@ describe('TranslateCompiler', () => {

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
providers: [
provideTranslateService({
loader: {provide: TranslateLoader, useClass: FakeLoader},
compiler: {provide: TranslateCompiler, useClass: CustomCompiler}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class AppComponent {
}
}

describe('TranslateDirective', () => {
describe('TranslateDirective (modules)', () => {
let translate: TranslateService;
let fixture: ComponentFixture<AppComponent>;

Expand Down
268 changes: 268 additions & 0 deletions projects/ngx-translate/src/lib/translate.directive-standalone.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import {ChangeDetectionStrategy, Component, ElementRef, Injectable, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {
provideTranslateService, TranslateDirective, TranslatePipe,
TranslateService
} from "../public-api";

@Injectable()
@Component({
selector: 'lib-hmx-app',
standalone: true,
imports: [TranslateDirective, TranslatePipe],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div #noKey translate>TEST</div>
<div #contentAsKey translate>TEST.VALUE</div>
<div #withKey [translate]="'TEST'">Some init content</div>
<div #noContent [translate]="'TEST'"></div>
<div #withOtherElements translate>TEST1 <span>Hey</span> TEST2</div>
<div #withParams [translate]="'TEST'" [translateParams]="value">Some init content</div>
<div #withParamsNoKey translate [translateParams]="value">TEST</div>
<div #leadingSpaceNoKeyNoParams translate> TEST</div>
<div #trailingSpaceNoKeyNoParams translate>TEST </div>
<div #withSpaceAndLineBreakNoKeyNoParams translate>
TEST
</div>
`
})
class AppComponent {
viewContainerRef: ViewContainerRef;
@ViewChild('noKey', {static: true}) noKey!: ElementRef;
@ViewChild('contentAsKey', {static: true}) contentAsKey!: ElementRef;
@ViewChild('withKey', {static: true}) withKey!: ElementRef;
@ViewChild('withOtherElements', {static: true}) withOtherElements!: ElementRef;
@ViewChild('withParams', {static: true}) withParams!: ElementRef;
@ViewChild('withParamsNoKey', {static: true}) withParamsNoKey!: ElementRef;
@ViewChild('noContent', {static: true}) noContent!: ElementRef;
@ViewChild('leadingSpaceNoKeyNoParams') leadingSpaceNoKeyNoParams!: ElementRef;
@ViewChild('trailingSpaceNoKeyNoParams') trailingSpaceNoKeyNoParams!: ElementRef;
@ViewChild('withSpaceAndLineBreakNoKeyNoParams') withSpaceAndLineBreakNoKeyNoParams!: ElementRef;
value = {value: 'ok'};

constructor(viewContainerRef: ViewContainerRef) {
this.viewContainerRef = viewContainerRef;
}
}

describe('TranslateDirective (standalone)', () => {
let translate: TranslateService;
let fixture: ComponentFixture<AppComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideTranslateService({})
]
});
translate = TestBed.inject(TranslateService);

fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
});

it('should translate a string using the container value', () => {
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {"TEST": "This is a test"});
translate.use('en');

expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('This is a test');
});

it('should translate a string using the container value as a key', () => {
expect(fixture.componentInstance.contentAsKey.nativeElement.innerHTML).toEqual('TEST.VALUE');

translate.setTranslation('en', {"TEST": {"VALUE": "This is a test"}});
translate.use('en');

expect(fixture.componentInstance.contentAsKey.nativeElement.innerHTML).toEqual('This is a test');
});

it('should translate a string using the key value', () => {
// replace the content with the key
expect(fixture.componentInstance.withKey.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {"TEST": "This is a test"});
translate.use('en');

expect(fixture.componentInstance.withKey.nativeElement.innerHTML).toEqual('This is a test');
});

it('should translate first child strings with elements in the middle', () => {
// replace the content with the key
expect(fixture.componentInstance.withOtherElements.nativeElement.innerHTML).toEqual('TEST1 <span>Hey</span> TEST2');

translate.setTranslation('en', {"TEST1": "Awesome", "TEST2": "it works"});
translate.use('en');

expect(fixture.componentInstance.withOtherElements.nativeElement.innerHTML).toEqual('Awesome <span>Hey</span> it works');
});

it('should translate first child strings without recursion', () => {
// replace the content with the key
expect(fixture.componentInstance.withOtherElements.nativeElement.innerHTML).toEqual('TEST1 <span>Hey</span> TEST2');

translate.setTranslation('en', {"TEST1": "TEST2", "TEST2": "it works"});
translate.use('en');

expect(fixture.componentInstance.withOtherElements.nativeElement.innerHTML).toEqual('TEST2 <span>Hey</span> it works');
});

it('should translate a string with params and a key', () => {
// replace the content with the key
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {"TEST": "It is {{value}}"});
translate.use('en');

expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('It is ok');
});

it('should translate a string with params and no key', () => {
// replace the content with the key
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {"TEST": "It is {{value}}"});
translate.use('en');

expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('It is ok');
});

it('should update the translation when params change', () => {
// replace the content with the key
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('TEST');
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {"TEST": "It is {{value}}"});
translate.use('en');

expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('It is ok');
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('It is ok');
fixture.componentInstance.value = {value: 'changed'};
fixture.detectChanges();

expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('It is changed');
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('It is changed');
});

it('should update the DOM when the lang changes and the translation key starts with space', () => {
expect(fixture.componentInstance.leadingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual(' TEST');

const en = "This is a test - with leading spaces in translation key";
const fr = "C'est un test - avec un espace de tête dans la clé de traduction";
const leadingSpaceFromKey = ' ';
translate.setTranslation('en', {"TEST": en});
translate.setTranslation('fr', {"TEST": fr});

translate.use('en');
expect(fixture.componentInstance.leadingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual(leadingSpaceFromKey + en);

translate.use('fr');
expect(fixture.componentInstance.leadingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual(leadingSpaceFromKey + fr);
});

it('should update the DOM when the lang changes and the translation key has line breaks and spaces', () => {
expect(fixture.componentInstance.withSpaceAndLineBreakNoKeyNoParams.nativeElement.innerHTML).toEqual(' TEST ');

const en = "This is a test - with trailing spaces in translation key";
const fr = "C'est un test - avec un espace de fuite dans la clé de traduction";
const whiteSpaceFromKey = ' ';
translate.setTranslation('en', {"TEST": en});
translate.setTranslation('fr', {"TEST": fr});

translate.use('en');
expect(fixture.componentInstance.withSpaceAndLineBreakNoKeyNoParams.nativeElement.innerHTML).toEqual(whiteSpaceFromKey + en + whiteSpaceFromKey);

translate.use('fr');
expect(fixture.componentInstance.withSpaceAndLineBreakNoKeyNoParams.nativeElement.innerHTML).toEqual(whiteSpaceFromKey + fr + whiteSpaceFromKey);
});

it('should update the DOM when the lang changes and the translation key ends with space', () => {
expect(fixture.componentInstance.trailingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual('TEST ');

const en = "This is a test - with spaces and line breaks in translation key";
const fr = "C'est un test - avec des espaces et sauts de lignes dans la clé de traduction";
const trailingSpaceFromKey = ' ';
translate.setTranslation('en', {"TEST": en});
translate.setTranslation('fr', {"TEST": fr});

translate.use('en');
expect(fixture.componentInstance.trailingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual(en + trailingSpaceFromKey);

translate.use('fr');
expect(fixture.componentInstance.trailingSpaceNoKeyNoParams.nativeElement.innerHTML).toEqual(fr + trailingSpaceFromKey);
});


it('should update the DOM when the lang changes and the translation ends with space', () => {
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('TEST');
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('TEST');
expect(fixture.componentInstance.noContent.nativeElement.innerHTML).toEqual('TEST');

const en = " This is a test - with spaces ";
const fr = " C'est un test - avec espaces ";

translate.setTranslation('en', {"TEST": en});
translate.setTranslation('fr', {"TEST": fr});

translate.use('en');
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual(`${en}`);
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual(en);
expect(fixture.componentInstance.noContent.nativeElement.innerHTML).toEqual(en);

translate.use('fr');
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual(`${fr}`);
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual(fr);
expect(fixture.componentInstance.noContent.nativeElement.innerHTML).toEqual(fr);
});

it('should update the DOM when the default lang changes', () => {
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('TEST');

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

translate.setDefaultLang('fr');
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual("C'est un test");
});

it('should unsubscribe from lang change subscription on destroy', () => {
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');

fixture.destroy();

translate.setTranslation('en', {"TEST": "This is a test"});
translate.use('en');

expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');
});

it('should unsubscribe from default lang change subscription on destroy', () => {
expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');

fixture.destroy();

translate.setTranslation('en', {"TEST": "This is a test"});
translate.setDefaultLang('en');

expect(fixture.componentInstance.withParamsNoKey.nativeElement.innerHTML).toEqual('TEST');
});

it('should update the DOM when the translation changes', () => {
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('TEST');
expect(fixture.componentInstance.withParams.nativeElement.innerHTML).toEqual('TEST');
expect(fixture.componentInstance.noContent.nativeElement.innerHTML).toEqual('TEST');

translate.setTranslation('en', {'TEST': 'first text'});
translate.use('en');
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('first text');

translate.setTranslation('en', {'TEST': 'updated text'});
expect(fixture.componentInstance.noKey.nativeElement.innerHTML).toEqual('updated text');
});


});
Loading

0 comments on commit c5c5798

Please sign in to comment.