diff --git a/lib/content-services/package.json b/lib/content-services/package.json index 03a3e4791b..b3da41540b 100644 --- a/lib/content-services/package.json +++ b/lib/content-services/package.json @@ -22,7 +22,7 @@ "@angular/platform-browser-dynamic": ">=14.1.3", "@angular/router": ">=14.1.3", "@alfresco/js-api": ">=9.3.1", - "@ngx-translate/core": ">=16.0.0", + "@ngx-translate/core": ">=17.0.0", "@alfresco/adf-core": ">=8.3.1" }, "keywords": [ diff --git a/lib/core/package.json b/lib/core/package.json index 3e92d78f4d..a36512053f 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -37,7 +37,7 @@ "@angular/platform-browser": ">=16.0.0", "@angular/router": ">=16.0.0", "@mat-datetimepicker/core": ">=12.0.1", - "@ngx-translate/core": ">=16.0.0", + "@ngx-translate/core": ">=17.0.0", "@alfresco/js-api": ">=9.3.1", "@alfresco/adf-extensions": ">=8.3.1", "minimatch": ">=10.0.0", diff --git a/lib/core/src/lib/core.module.ts b/lib/core/src/lib/core.module.ts index 2dae18a8fd..c5b808f153 100644 --- a/lib/core/src/lib/core.module.ts +++ b/lib/core/src/lib/core.module.ts @@ -16,7 +16,7 @@ */ import { NgModule, ModuleWithProviders } from '@angular/core'; -import { TranslateLoader, provideTranslateService } from '@ngx-translate/core'; +import { provideTranslateService, provideTranslateLoader } from '@ngx-translate/core'; import { ABOUT_DIRECTIVES } from './about/about.module'; import { CARD_VIEW_DIRECTIVES } from './card-view/card-view.module'; import { CONTEXT_MENU_DIRECTIVES } from './context-menu/context-menu.module'; @@ -38,7 +38,6 @@ import { CORE_DIRECTIVES } from './directives/directive.module'; import { CORE_PIPES } from './pipes/pipe.module'; import { TranslateLoaderService } from './translation/translate-loader.service'; import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module'; -import { HttpClient } from '@angular/common/http'; import { AppConfigPipe } from './app-config'; import { IconComponent } from './icon'; import { DynamicChipListComponent } from './dynamic-chip-list'; @@ -123,12 +122,8 @@ export class CoreModule { ngModule: CoreModule, providers: [ provideTranslateService({ - loader: { - provide: TranslateLoader, - useClass: TranslateLoaderService, - deps: [HttpClient] - }, - defaultLanguage: 'en' + loader: provideTranslateLoader(TranslateLoaderService), + fallbackLang: 'en' }), provideAppConfig() ] diff --git a/lib/core/src/lib/testing/noop-translate.module.ts b/lib/core/src/lib/testing/noop-translate.module.ts index 846c389c67..b7bb9a6d34 100644 --- a/lib/core/src/lib/testing/noop-translate.module.ts +++ b/lib/core/src/lib/testing/noop-translate.module.ts @@ -18,19 +18,20 @@ import { EventEmitter, Injectable, NgModule } from '@angular/core'; import { provideHttpClient } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { provideTranslateService, TranslateLoader } from '@ngx-translate/core'; +import { Language, provideTranslateLoader, provideTranslateService, TranslateLoader, TranslationObject } from '@ngx-translate/core'; import { TranslationService } from '../translation/translation.service'; import { LangChangeEvent } from '../mock'; import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root' }) -export class NoopTranslationService { +export class NoopTranslationService implements TranslateLoader { defaultLang: string = 'en'; userLang: string; customLoader: any; translate: any = { - onLangChange: new EventEmitter() + onLangChange: new EventEmitter(), + getCurrentLang: (): Language => 'en' }; addTranslationFolder() {} @@ -47,6 +48,10 @@ export class NoopTranslationService { instant(key: string | Array): string | any { return key; } + + getTranslation(_lang: string): Observable { + return of({}); + } } @NgModule({ @@ -55,10 +60,7 @@ export class NoopTranslationService { provideHttpClientTesting(), { provide: TranslationService, useClass: NoopTranslationService }, provideTranslateService({ - loader: { - provide: TranslateLoader, - useClass: NoopTranslationService - } + loader: provideTranslateLoader(NoopTranslationService) }) ] }) diff --git a/lib/core/src/lib/translation/provide-i18n.spec.ts b/lib/core/src/lib/translation/provide-i18n.spec.ts index ce04356d56..cb93f3a9fc 100644 --- a/lib/core/src/lib/translation/provide-i18n.spec.ts +++ b/lib/core/src/lib/translation/provide-i18n.spec.ts @@ -40,7 +40,7 @@ describe('provideI18N', () => { it('should set default language to "en" when not specified', () => { const translateService = TestBed.inject(TranslateService); - expect(translateService.defaultLang).toBe('en'); + expect(translateService.getFallbackLang()).toBe('en'); }); }); @@ -53,7 +53,7 @@ describe('provideI18N', () => { it('should set custom default language', () => { const translateService = TestBed.inject(TranslateService); - expect(translateService.defaultLang).toBe('fr'); + expect(translateService.getFallbackLang()).toBe('fr'); }); }); @@ -81,7 +81,7 @@ describe('provideI18N', () => { // Services should be properly configured expect(translateService).toBeDefined(); expect(translationService).toBeDefined(); - expect(translateService.defaultLang).toBe('en'); + expect(translateService.getFallbackLang()).toBe('en'); }); }); @@ -153,7 +153,7 @@ describe('provideI18N', () => { it('should set translations for custom default language', () => { const translateService = TestBed.inject(TranslateService); - expect(translateService.defaultLang).toBe('fr'); + expect(translateService.getFallbackLang()).toBe('fr'); expect(translateService.instant('HELLO')).toBe('Bonjour!'); }); }); @@ -184,7 +184,7 @@ describe('provideI18N', () => { const translateService = TestBed.inject(TranslateService); const loader = translateService.currentLoader as TranslateLoaderService; - expect(translateService.defaultLang).toBe('en'); + expect(translateService.getFallbackLang()).toBe('en'); expect(loader).toBeDefined(); expect(loader.providerRegistered).toBeDefined(); expect(loader.providerRegistered('adf-core')).toBeTruthy(); @@ -211,7 +211,7 @@ describe('provideI18N', () => { it('should handle empty translations object', () => { const translateService = TestBed.inject(TranslateService); expect(translateService).toBeDefined(); - expect(translateService.defaultLang).toBe('en'); + expect(translateService.getFallbackLang()).toBe('en'); }); }); }); diff --git a/lib/core/src/lib/translation/provide-i18n.ts b/lib/core/src/lib/translation/provide-i18n.ts index 6ba9520ad3..65a364d8e9 100644 --- a/lib/core/src/lib/translation/provide-i18n.ts +++ b/lib/core/src/lib/translation/provide-i18n.ts @@ -16,9 +16,8 @@ */ import { EnvironmentProviders, inject, provideAppInitializer, Provider } from '@angular/core'; -import { provideTranslateService, TranslateLoader, TranslateService } from '@ngx-translate/core'; +import { provideTranslateLoader, provideTranslateService, TranslateService } from '@ngx-translate/core'; import { TranslateLoaderService } from './translate-loader.service'; -import { HttpClient } from '@angular/common/http'; import { provideTranslations } from './translation.service'; export interface ProvideI18NConfig { @@ -54,12 +53,8 @@ export function provideI18N(config?: ProvideI18NConfig): (Provider | Environment const result: (Provider | EnvironmentProviders)[] = [ provideTranslateService({ - loader: { - provide: TranslateLoader, - useExisting: TranslateLoaderService, - deps: [HttpClient] - }, - defaultLanguage + loader: provideTranslateLoader(TranslateLoaderService), + fallbackLang: defaultLanguage }) ]; diff --git a/lib/core/src/lib/translation/translate-loader.service.ts b/lib/core/src/lib/translation/translate-loader.service.ts index 3b1939480b..d48656a8eb 100644 --- a/lib/core/src/lib/translation/translate-loader.service.ts +++ b/lib/core/src/lib/translation/translate-loader.service.ts @@ -147,10 +147,10 @@ export class TranslateLoaderService implements TranslateLoader { forkJoin(batch).subscribe({ next: () => { const fullTranslation = this.getFullTranslationJSON(lang); - if (fullTranslation) { + if (Object.keys(fullTranslation).length) { observer.next(fullTranslation); - } - if (hasFailures) { + observer.complete(); + } else if (hasFailures) { observer.error('Failed to load some resources'); } else { observer.complete(); diff --git a/lib/core/src/lib/translation/translate-loader.spec.ts b/lib/core/src/lib/translation/translate-loader.spec.ts index a6bfaaac99..d1da33693c 100644 --- a/lib/core/src/lib/translation/translate-loader.spec.ts +++ b/lib/core/src/lib/translation/translate-loader.spec.ts @@ -15,42 +15,49 @@ * limitations under the License. */ -import { TestBed } from '@angular/core/testing'; +import { fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { TranslateLoaderService } from './translate-loader.service'; -import { TranslationService } from './translation.service'; -import { provideTranslateService, TranslateLoader } from '@ngx-translate/core'; -import { HttpClient } from '@angular/common/http'; describe('TranslateLoader', () => { - let translationService: TranslationService; let customLoader: TranslateLoaderService; + let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ - providers: [ - provideTranslateService({ - loader: { - provide: TranslateLoader, - useClass: TranslateLoaderService, - deps: [HttpClient] - }, - defaultLanguage: 'en' - }), - TranslationService - ] + providers: [provideHttpClientTesting(), TranslateLoaderService] }); - translationService = TestBed.inject(TranslationService); - customLoader = translationService.translate.currentLoader as TranslateLoaderService; + customLoader = TestBed.inject(TranslateLoaderService); + httpMock = TestBed.inject(HttpTestingController); }); - it('should be able to provide any TranslateLoader', () => { - expect(translationService).toBeDefined(); - expect(translationService.translate.currentLoader).toBeDefined(); - expect(translationService.translate.currentLoader instanceof TranslateLoaderService).toBeTruthy(); + it('should be able to provide TranslateLoaderService', () => { + expect(customLoader).toBeDefined(); + expect(customLoader instanceof TranslateLoaderService).toBeTruthy(); }); it('should add the component to the list', () => { customLoader.registerProvider('login', 'path/login'); expect(customLoader.providerRegistered('login')).toBeTruthy(); }); + + it('should complete observer when gets full translation json', fakeAsync(() => { + const language = 'en'; + let nextInvoked = false; + let completeInvoked = false; + + const subscription = customLoader.getTranslation(language).subscribe({ + next: () => (nextInvoked = true), + error: () => fail('Should not call error handler'), + complete: () => (completeInvoked = true) + }); + const expectedRequest = httpMock.expectOne((request) => request.url.includes(`assets/adf-core/i18n/${language}.json`)); + expect(expectedRequest.request.method).toBe('GET'); + expectedRequest.flush({ 'TEST.COMPONENT': 'Composant de test' }); + tick(); + expect(nextInvoked).toBeTrue(); + expect(completeInvoked).toBeTrue(); + subscription.unsubscribe(); + httpMock.verify(); + })); }); diff --git a/lib/core/src/lib/translation/translation.service.spec.ts b/lib/core/src/lib/translation/translation.service.spec.ts index dc06242cbf..a580237ec7 100644 --- a/lib/core/src/lib/translation/translation.service.spec.ts +++ b/lib/core/src/lib/translation/translation.service.spec.ts @@ -16,7 +16,7 @@ */ import { TestBed } from '@angular/core/testing'; -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { provideTranslateLoader, provideTranslateService, TranslateLoader } from '@ngx-translate/core'; import { TranslationService } from './translation.service'; import { of } from 'rxjs'; import { provideAppConfigTesting } from '../testing'; @@ -51,15 +51,13 @@ describe('TranslationService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: FakeLoader - } + providers: [ + TranslationService, + provideAppConfigTesting(), + provideTranslateService({ + loader: provideTranslateLoader(FakeLoader) }) - ], - providers: [TranslationService, provideAppConfigTesting()] + ] }); translationService = TestBed.inject(TranslationService); diff --git a/lib/core/src/lib/translation/translation.service.ts b/lib/core/src/lib/translation/translation.service.ts index f0f64ca270..94a57d46b0 100644 --- a/lib/core/src/lib/translation/translation.service.ts +++ b/lib/core/src/lib/translation/translation.service.ts @@ -62,7 +62,7 @@ export class TranslationService { this.customLoader = this.translate.currentLoader as TranslateLoaderService; this.defaultLang = 'en'; - this.translate.setDefaultLang(this.defaultLang); + this.translate.setFallbackLang(this.defaultLang); this.customLoader.setDefaultLang(this.defaultLang); if (this.providers && this.providers.length > 0) { @@ -115,7 +115,7 @@ export class TranslationService { * @param fallback Language code to fall back to if the first one was unavailable */ loadTranslation(lang: string, fallback?: string) { - this.translate.getTranslation(lang).subscribe( + this.translate.currentLoader.getTranslation(lang).subscribe( () => { this.translate.use(lang); this.onTranslationChanged(lang); @@ -134,10 +134,8 @@ export class TranslationService { * @param lang The new language code */ onTranslationChanged(lang: string): void { - this.translate.onTranslationChange.next({ - lang, - translations: this.customLoader.getFullTranslationJSON?.(lang) ?? {} - }); + const translations = this.customLoader.getFullTranslationJSON?.(lang) ?? {}; + this.translate.setTranslation(lang, translations, true); } /** diff --git a/lib/insights/package.json b/lib/insights/package.json index b9ca5faf6b..01a5b3bb26 100644 --- a/lib/insights/package.json +++ b/lib/insights/package.json @@ -13,7 +13,7 @@ "dependencies": { "@alfresco/adf-core": ">=8.3.1", "@alfresco/adf-content-services": ">=8.3.1", - "@ngx-translate/core": ">=14.0.0", + "@ngx-translate/core": ">=17.0.0", "chart.js": "^4.3.0", "ng2-charts": "^4.1.1", "raphael": ">=2.3.0" diff --git a/lib/process-services-cloud/package.json b/lib/process-services-cloud/package.json index afc229564a..aa31b34042 100644 --- a/lib/process-services-cloud/package.json +++ b/lib/process-services-cloud/package.json @@ -25,7 +25,7 @@ "@alfresco/adf-core": ">=8.3.1", "@alfresco/adf-content-services": ">=8.3.1", "@apollo/client": ">=3.7.2", - "@ngx-translate/core": ">=14.0.0", + "@ngx-translate/core": ">=17.0.0", "apollo-angular": ">=4.0.1", "editorjs-html": "^4.0.5" }, diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts index 496586b024..1b7268e11c 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts @@ -45,7 +45,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialog } from '@angular/material/dialog'; import { MatDialogHarness } from '@angular/material/dialog/testing'; import { By } from '@angular/platform-browser'; -import { TranslateLoader, TranslateService, provideTranslateService } from '@ngx-translate/core'; +import { TranslateLoader, TranslateService, provideTranslateService, provideTranslateLoader } from '@ngx-translate/core'; import { firstValueFrom, Observable, of, throwError } from 'rxjs'; import { cloudFormMock, @@ -1746,10 +1746,7 @@ describe('Multilingual Form', () => { imports: [NoopAuthModule], providers: [ provideTranslateService({ - loader: { - provide: TranslateLoader, - useClass: FakeLoader - } + loader: provideTranslateLoader(FakeLoader) }) ] }); diff --git a/lib/process-services/package.json b/lib/process-services/package.json index 27cc5eb656..1fc69912d7 100644 --- a/lib/process-services/package.json +++ b/lib/process-services/package.json @@ -24,7 +24,7 @@ "@alfresco/js-api": ">=9.3.1", "@alfresco/adf-core": ">=8.3.1", "@alfresco/adf-content-services": ">=8.3.1", - "@ngx-translate/core": ">=14.0.0" + "@ngx-translate/core": ">=17.0.0" }, "keywords": [ "process-services", diff --git a/package-lock.json b/package-lock.json index fbbe346767..cc4906be87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@apollo/client": "3.13.1", "@cspell/eslint-plugin": "9.4.0", "@mat-datetimepicker/core": "15.0.2", - "@ngx-translate/core": "^16.0.4", + "@ngx-translate/core": "^17.0.0", "angular-oauth2-oidc": "17.0.2", "angular-oauth2-oidc-jwks": "^17.0.2", "apollo-angular": "10.0.3", @@ -8953,9 +8953,9 @@ "license": "MIT" }, "node_modules/@ngx-translate/core": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-16.0.4.tgz", - "integrity": "sha512-s8llTL2SJvROhqttxvEs7Cg+6qSf4kvZPFYO+cTOY1d8DWTjlutRkWAleZcPPoeX927Dm7ALfL07G7oYDJ7z6w==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-17.0.0.tgz", + "integrity": "sha512-Rft2D5ns2pq4orLZjEtx1uhNuEBerUdpFUG1IcqtGuipj6SavgB8SkxtNQALNDA+EVlvsNCCjC2ewZVtUeN6rg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" diff --git a/package.json b/package.json index b58f26f6c3..d2da815e04 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@apollo/client": "3.13.1", "@cspell/eslint-plugin": "9.4.0", "@mat-datetimepicker/core": "15.0.2", - "@ngx-translate/core": "^16.0.4", + "@ngx-translate/core": "^17.0.0", "angular-oauth2-oidc": "17.0.2", "angular-oauth2-oidc-jwks": "^17.0.2", "apollo-angular": "10.0.3",