[ADF-3630] fix i18n fallback behaviour (#3851)

* fix i18n fallback behaviour

* update tests

* update tests

* configuration fixes

* test configuration fix
This commit is contained in:
Denys Vuika
2018-10-04 10:11:30 +01:00
committed by Eugenio Romano
parent d1f87837ac
commit 54cca45ec1
12 changed files with 126 additions and 92 deletions

View File

@@ -3,41 +3,43 @@
module.exports = function (config) { module.exports = function (config) {
config.set({ config.set({
basePath: '', basePath: '../../',
files: [ files: [
{pattern: '../../node_modules/core-js/client/core.js', included: true, watched: false}, {pattern: 'node_modules/core-js/client/core.js', included: true, watched: false},
{pattern: '../../node_modules/tslib/tslib.js', included: true, watched: false}, {pattern: 'node_modules/tslib/tslib.js', included: true, watched: false},
{pattern: '../../node_modules/hammerjs/hammer.min.js', included: true, watched: false}, {pattern: 'node_modules/hammerjs/hammer.min.js', included: true, watched: false},
{pattern: '../../node_modules/hammerjs/hammer.min.js.map', included: false, watched: false}, {pattern: 'node_modules/hammerjs/hammer.min.js.map', included: false, watched: false},
// pdf-js // pdf-js
{pattern: '../../node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false},
{pattern: '../../node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false},
{pattern: '../../node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false},
{ {
pattern: '../../node_modules/@angular/material/prebuilt-themes/indigo-pink.css', pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css',
included: true, included: true,
watched: false watched: false
}, },
{pattern: '../../node_modules/alfresco-js-api/dist/alfresco-js-api.min.js', included: true, watched: false}, {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.min.js', included: true, watched: false},
{pattern: '../../node_modules/moment/min/moment.min.js', included: true, watched: false}, {pattern: 'node_modules/moment/min/moment.min.js', included: true, watched: false},
{pattern: './i18n/**/en.json', included: false, served: true, watched: false}, {pattern: 'lib/content-services/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: 'lib/core/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: './**/*.ts', included: false, served: true, watched: false}, {pattern: 'lib/content-services/**/*.ts', included: false, served: true, watched: false},
{pattern: './app.config.json', included: false, served: true, watched: false}, {pattern: 'lib/config/app.config.json', included: false, served: true, watched: false},
], ],
frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'], frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'],
proxies: { proxies: {
'/base/assets/' :'/base/assets/', '/base/assets/' :'/base/lib/content-services/assets/',
'/assets/adf-content-services/i18n/en.json': '/base/i18n/en.json', '/assets/adf-content-services/i18n/en.json': '/base/lib/content-services/i18n/en.json',
'/app.config.json': '/base/app.config.json' '/assets/adf-core/i18n/en.json': '/base/lib/core/i18n/en.json',
'/app.config.json': '/base/lib/config/app.config.json',
}, },
plugins: [ plugins: [

View File

@@ -100,8 +100,8 @@ import { ViewUtilService } from './viewer/services/view-util.service';
import { LoginDialogService } from './services/login-dialog.service'; import { LoginDialogService } from './services/login-dialog.service';
import { ExternalAlfrescoApiService } from './services/external-alfresco-api.service'; import { ExternalAlfrescoApiService } from './services/external-alfresco-api.service';
export function createTranslateLoader(http: HttpClient, logService: LogService) { export function createTranslateLoader(http: HttpClient) {
return new TranslateLoaderService(http, logService); return new TranslateLoaderService(http);
} }
export function providers() { export function providers() {

View File

@@ -28,11 +28,11 @@ module.exports = function (config) {
{pattern: 'lib/core/i18n/**/en.json', included: false, served: true, watched: false}, {pattern: 'lib/core/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: 'lib/core/./**/*.ts', included: false, served: true, watched: false}, {pattern: 'lib/core/**/*.ts', included: false, served: true, watched: false},
{pattern: 'lib/core/assets/**/*.svg', included: false, served: true, watched: false}, {pattern: 'lib/core/assets/**/*.svg', included: false, served: true, watched: false},
{pattern: 'lib/config/app.config.json', included: false, served: true, watched: false}, {pattern: 'lib/config/app.config.json', included: false, served: true, watched: false},
{pattern: 'lib/core//viewer/assets/fake-test-file.pdf', included: false, served: true, watched: false}, {pattern: 'lib/core/viewer/assets/fake-test-file.pdf', included: false, served: true, watched: false},
{pattern: 'lib/core/viewer/assets/fake-test-file.txt', included: false, served: true, watched: false}, {pattern: 'lib/core/viewer/assets/fake-test-file.txt', included: false, served: true, watched: false},
{ {
pattern: 'lib/core//viewer/assets/fake-test-password-file.pdf', pattern: 'lib/core//viewer/assets/fake-test-password-file.pdf',

View File

@@ -34,17 +34,13 @@ export class TranslationMock implements TranslationService {
onLangChange: new EventEmitter<LangChangeEvent>() onLangChange: new EventEmitter<LangChangeEvent>()
}; };
addTranslationFolder() { addTranslationFolder() {}
} onTranslationChanged() {}
onTranslationChanged() { use(): any {}
} loadTranslation() {}
use(): any {
}
get(key: string | Array<string>, interpolateParams?: Object): Observable<string | any> { get(key: string | Array<string>, interpolateParams?: Object): Observable<string | any> {
return of(key); return of(key);

View File

@@ -19,11 +19,10 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Response } from '@angular/http'; import { Response } from '@angular/http';
import { TranslateLoader } from '@ngx-translate/core'; import { TranslateLoader } from '@ngx-translate/core';
import { Observable, forkJoin } from 'rxjs'; import { Observable, forkJoin, throwError } from 'rxjs';
import { ComponentTranslationModel } from '../models/component.model'; import { ComponentTranslationModel } from '../models/component.model';
import { ObjectUtils } from '../utils/object-utils'; import { ObjectUtils } from '../utils/object-utils';
import { LogService } from './log.service'; import { map, catchError } from 'rxjs/operators';
import { map } from 'rxjs/operators';
@Injectable() @Injectable()
export class TranslateLoaderService implements TranslateLoader { export class TranslateLoaderService implements TranslateLoader {
@@ -33,8 +32,7 @@ export class TranslateLoaderService implements TranslateLoader {
private providers: ComponentTranslationModel[] = []; private providers: ComponentTranslationModel[] = [];
private queue: string [][] = []; private queue: string [][] = [];
constructor(private http: HttpClient, constructor(private http: HttpClient) {
private logService: LogService) {
} }
registerProvider(name: string, path: string) { registerProvider(name: string, path: string) {
@@ -59,21 +57,16 @@ export class TranslateLoaderService implements TranslateLoader {
if (!this.isComponentInQueue(lang, component.name)) { if (!this.isComponentInQueue(lang, component.name)) {
this.queue[lang].push(component.name); this.queue[lang].push(component.name);
const loader = Observable.create(observer => {
const translationUrl = `${component.path}/${this.prefix}/${lang}${this.suffix}?v=${Date.now()}`; const translationUrl = `${component.path}/${this.prefix}/${lang}${this.suffix}?v=${Date.now()}`;
this.http.get(translationUrl).pipe(map((res: Response) => { observableBatch.push(
this.http.get(translationUrl).pipe(
map((res: Response) => {
component.json[lang] = res; component.json[lang] = res;
})).subscribe((result) => { }),
observer.next(result); catchError(() => throwError(`Error loading ${translationUrl}`))
observer.complete(); )
}, () => { );
observer.next('');
observer.complete();
});
});
observableBatch.push(loader);
} }
}); });
@@ -114,7 +107,7 @@ export class TranslateLoaderService implements TranslateLoader {
} }
getTranslation(lang: string): Observable<any> { getTranslation(lang: string): Observable<any> {
let observableBatch = this.getComponentToFetch(lang); const observableBatch = this.getComponentToFetch(lang);
return Observable.create(observer => { return Observable.create(observer => {
if (observableBatch.length > 0) { if (observableBatch.length > 0) {
@@ -126,13 +119,14 @@ export class TranslateLoaderService implements TranslateLoader {
} }
observer.complete(); observer.complete();
}, },
(err: any) => { (err) => {
this.logService.error(err); observer.error(err);
}); });
} else { } else {
let fullTranslation = this.getFullTranslationJSON(lang); let fullTranslation = this.getFullTranslationJSON(lang);
if (fullTranslation) { if (fullTranslation) {
observer.next(fullTranslation); observer.next(fullTranslation);
observer.complete();
} }
} }
}); });

View File

@@ -62,21 +62,28 @@ export class TranslationService {
addTranslationFolder(name: string = '', path: string = '') { addTranslationFolder(name: string = '', path: string = '') {
if (!this.customLoader.providerRegistered(name)) { if (!this.customLoader.providerRegistered(name)) {
this.customLoader.registerProvider(name, path); this.customLoader.registerProvider(name, path);
if (this.userLang) { if (this.userLang) {
this.translate.getTranslation(this.userLang).subscribe(() => { this.loadTranslation(this.userLang, this.defaultLang);
this.translate.use(this.userLang);
this.onTranslationChanged(this.userLang);
}
);
} else { } else {
this.translate.getTranslation(this.defaultLang).subscribe(() => { this.loadTranslation(this.defaultLang);
this.translate.use(this.defaultLang); }
this.onTranslationChanged(this.defaultLang); }
}
loadTranslation(lang: string, fallback?: string) {
this.translate.getTranslation(lang).subscribe(
() => {
this.translate.use(lang);
this.onTranslationChanged(lang);
},
() => {
if (fallback && fallback !== lang) {
this.loadTranslation(fallback);
}
} }
); );
} }
}
}
/** /**
* Triggers a notification callback when the translation language changes. * Triggers a notification callback when the translation language changes.

View File

@@ -309,6 +309,10 @@ describe('Custom CustomEmptyTemplateComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => {
fixture.destroy();
});
it('should render the custom template', async(() => { it('should render the custom template', async(() => {
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -336,6 +336,10 @@ describe('Custom CustomEmptyTemplateComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => {
fixture.destroy();
});
it('should render the custom template', async(() => { it('should render the custom template', async(() => {
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -3,50 +3,53 @@
module.exports = function (config) { module.exports = function (config) {
config.set({ config.set({
basePath: '', basePath: '../../',
files: [ files: [
{pattern: '../../node_modules/core-js/client/core.js', included: true, watched: false}, {pattern: 'node_modules/core-js/client/core.js', included: true, watched: false},
{pattern: '../../node_modules/tslib/tslib.js', included: true, watched: false}, {pattern: 'node_modules/tslib/tslib.js', included: true, watched: false},
{pattern: '../../node_modules/hammerjs/hammer.min.js', included: true, watched: false}, {pattern: 'node_modules/hammerjs/hammer.min.js', included: true, watched: false},
{pattern: '../../node_modules/hammerjs/hammer.min.js.map', included: false, watched: false}, {pattern: 'node_modules/hammerjs/hammer.min.js.map', included: false, watched: false},
// pdf-js // pdf-js
{pattern: '../../node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false},
{pattern: '../../node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false},
{pattern: '../../node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false},
{ {
pattern: '../../node_modules/@angular/material/prebuilt-themes/indigo-pink.css', pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css',
included: true, included: true,
watched: false watched: false
}, },
{pattern: '../../node_modules/chart.js/dist/Chart.js', included: true, watched: false}, {pattern: 'node_modules/chart.js/dist/Chart.js', included: true, watched: false},
{pattern: '../../node_modules/raphael/raphael.min.js', included: true, watched: false}, {pattern: 'node_modules/raphael/raphael.min.js', included: true, watched: false},
{ {
pattern: './node_modules/ng2-charts/bundles/ng2-charts.umd.js', pattern: 'node_modules/ng2-charts/bundles/ng2-charts.umd.js',
included: false, included: false,
served: true, served: true,
watched: false watched: false
}, },
{pattern: '../../node_modules/alfresco-js-api/dist/alfresco-js-api.min.js', included: true, watched: false}, {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.min.js', included: true, watched: false},
{pattern: '../../node_modules/moment/min/moment.min.js', included: true, watched: false}, {pattern: 'node_modules/moment/min/moment.min.js', included: true, watched: false},
{pattern: './i18n/**/en.json', included: false, served: true, watched: false}, {pattern: 'lib/core/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: 'lib/content-services/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: 'lib/process-services/i18n/**/en.json', included: false, served: true, watched: false},
{pattern: './**/*.ts', included: false, served: true, watched: false}, {pattern: 'lib/process-services/**/*.ts', included: false, served: true, watched: false},
{pattern: 'lib/config/app.config.json', included: false, served: true, watched: false}
{pattern: './app.config.json', included: false, served: true, watched: false},
], ],
frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'], frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'],
proxies: { proxies: {
'/base/assets/' :'/base/assets/', '/base/assets/' :'/base/assets/',
'/assets/adf-process-services/i18n/en.json': '/base/i18n/en.json', '/assets/adf-core/i18n/en.json': '/base/lib/core/i18n/en.json',
'/app.config.json': '/base/app.config.json' '/assets/adf-content-services/i18n/en.json': '/base/lib/content-services/i18n/en.json',
'/assets/adf-process-services/i18n/en.json': '/base/lib/process-services/i18n/en.json',
'/app.config.json': '/base/lib/config/app.config.json'
}, },
plugins: [ plugins: [

View File

@@ -516,7 +516,7 @@ describe('CustomProcessListComponent', () => {
class EmptyTemplateComponent { class EmptyTemplateComponent {
} }
describe('Custom EmptyTemplateComponent', () => { describe('Process List: Custom EmptyTemplateComponent', () => {
let fixture: ComponentFixture<EmptyTemplateComponent>; let fixture: ComponentFixture<EmptyTemplateComponent>;
setupTestBed({ setupTestBed({
@@ -530,6 +530,10 @@ describe('Custom EmptyTemplateComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => {
fixture.destroy();
});
it('should render the custom template', async(() => { it('should render the custom template', async(() => {
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -16,7 +16,7 @@
*/ */
import { Component, SimpleChange, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { Component, SimpleChange, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { AppConfigService, setupTestBed, CoreModule } from '@alfresco/adf-core'; import { AppConfigService, setupTestBed, CoreModule } from '@alfresco/adf-core';
import { DataRowEvent, ObjectDataRow } from '@alfresco/adf-core'; import { DataRowEvent, ObjectDataRow } from '@alfresco/adf-core';
@@ -24,6 +24,8 @@ import { TaskListService } from '../services/tasklist.service';
import { TaskListComponent } from './task-list.component'; import { TaskListComponent } from './task-list.component';
import { ProcessTestingModule } from '../../testing/process.testing.module'; import { ProcessTestingModule } from '../../testing/process.testing.module';
import { fakeGlobalTask, fakeCutomSchema } from '../../mock'; import { fakeGlobalTask, fakeCutomSchema } from '../../mock';
import { TranslateService } from '@ngx-translate/core';
import { of } from 'rxjs';
declare let jasmine: any; declare let jasmine: any;
@@ -74,6 +76,7 @@ describe('TaskListComponent', () => {
afterEach(() => { afterEach(() => {
jasmine.Ajax.uninstall(); jasmine.Ajax.uninstall();
fixture.destroy();
}); });
it('should use the default schemaColumn as default', () => { it('should use the default schemaColumn as default', () => {
@@ -543,6 +546,10 @@ describe('CustomTaskListComponent', () => {
component = fixture.componentInstance; component = fixture.componentInstance;
}); });
afterEach(() => {
fixture.destroy();
});
it('should create instance of CustomTaskListComponent', () => { it('should create instance of CustomTaskListComponent', () => {
expect(component instanceof CustomTaskListComponent).toBe(true, 'should create CustomTaskListComponent'); expect(component instanceof CustomTaskListComponent).toBe(true, 'should create CustomTaskListComponent');
}); });
@@ -568,8 +575,9 @@ describe('CustomTaskListComponent', () => {
class EmptyTemplateComponent { class EmptyTemplateComponent {
} }
describe('Custom EmptyTemplateComponent', () => { describe('Task List: Custom EmptyTemplateComponent', () => {
let fixture: ComponentFixture<EmptyTemplateComponent>; let fixture: ComponentFixture<EmptyTemplateComponent>;
let translateService: TranslateService;
setupTestBed({ setupTestBed({
imports: [ProcessTestingModule], imports: [ProcessTestingModule],
@@ -578,15 +586,23 @@ describe('Custom EmptyTemplateComponent', () => {
}); });
beforeEach(() => { beforeEach(() => {
translateService = TestBed.get(TranslateService);
spyOn(translateService, 'get').and.callFake((key) => {
return of(key);
});
fixture = TestBed.createComponent(EmptyTemplateComponent); fixture = TestBed.createComponent(EmptyTemplateComponent);
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should render the custom template', async(() => { afterEach(() => {
fixture.whenStable().then(() => { fixture.destroy();
});
it('should render the custom template', fakeAsync(() => {
fixture.detectChanges(); fixture.detectChanges();
tick(100);
expect(fixture.debugElement.query(By.css('#custom-id'))).not.toBeNull(); expect(fixture.debugElement.query(By.css('#custom-id'))).not.toBeNull();
expect(fixture.debugElement.query(By.css('.adf-empty-content'))).toBeNull(); expect(fixture.debugElement.query(By.css('.adf-empty-content'))).toBeNull();
});
})); }));
}); });

View File

@@ -31,12 +31,16 @@ describe('TaskStandaloneComponent', () => {
] ]
}); });
beforeEach(async(() => { beforeEach(() => {
fixture = TestBed.createComponent(TaskStandaloneComponent); fixture = TestBed.createComponent(TaskStandaloneComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;
fixture.detectChanges(); fixture.detectChanges();
})); });
afterEach(() => {
fixture.destroy();
});
it('should show Completed message if isCompleted is true', async(() => { it('should show Completed message if isCompleted is true', async(() => {
component.isCompleted = true; component.isCompleted = true;