Skip to content

Commit

Permalink
feat(service-navigation/web-component): add language input property
Browse files Browse the repository at this point in the history
OUI-3268
  • Loading branch information
dariopog-foitt authored and nina-egger committed Oct 1, 2024
1 parent 53f33ce commit cff248d
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {ObICustomButton, ObILink} from './service-navigation-web-component.model
export class ObServiceNavigationWebComponentComponent implements OnChanges, OnInit {
@Input() languageList: string;
@Input() defaultLanguage: string;
@Input() language: string;
@Input() environment: 'DEV' | 'REF' | 'TEST' | 'ABN' | 'PROD';
@Input() infoContact: string;
@Input() infoLinks: string;
Expand Down Expand Up @@ -82,10 +83,11 @@ export class ObServiceNavigationWebComponentComponent implements OnChanges, OnIn
this.profileLinksParsed = this.parseLinks(changes.profileLinks, 'profile');
this.customButtonsParsed = this.parseCustomButtons(changes.customButtons);
this.translationService.handleTranslations(this.infoLinks, this.profileLinks);
this.handleNewLanguage(changes.language);
}

ngOnInit(): void {
this.translationService.initializeTranslations(this.languageList, this.defaultLanguage);
this.translationService.initializeTranslations(this.languageList, this.language, this.defaultLanguage);
this.translationService.handleTranslations(this.infoLinks, this.profileLinks); // necessary because ngOnChanges is called before ngOnInit
this.environmentParsed = this.parseEnvironment(this.environment);
}
Expand Down Expand Up @@ -119,4 +121,10 @@ export class ObServiceNavigationWebComponentComponent implements OnChanges, OnIn
private parseCustomButtons(customButtons: SimpleChange | undefined): ObICustomButton[] {
return customButtons ? JSON.parse(customButtons.currentValue || '[]') : this.customButtonsParsed;
}

private handleNewLanguage(language: SimpleChange | undefined): void {
if (language) {
this.translationService.setLang(language.currentValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,30 @@ describe(TranslationsService.name, () => {
});
});

describe('setLang', () => {
it('should call use', () => {
jest.spyOn(translate, 'use');
service.initializeTranslations('en,fr', 'fr', 'fr');
service.setLang('en');
expect(translate.use).toHaveBeenCalledWith('en');
});
});

describe('initializeTranslations', () => {
describe('parseLanguages', () => {
it('should fail when using wrong languages format', () => {
const func = (): void => service.initializeTranslations('en,error', undefined);
const func = (): void => service.initializeTranslations('en,error', undefined, undefined);
expect(func).toThrow(`"language-list" expects a comma`);
});

it('should fail when using unknown language `zz` is used', () => {
const func = (): void => service.initializeTranslations('en,zz', undefined);
const func = (): void => service.initializeTranslations('en,zz', undefined, undefined);
expect(func).toThrow(`Unknown "zz" language`);
});

it('should find en,fr,de in the translate service', () => {
const languageList = ['en', 'fr', 'de', 'it'];
service.initializeTranslations(languageList.join(','), undefined);
service.initializeTranslations(languageList.join(','), undefined, undefined);

expect(translate.langs).toEqual(languageList);
});
Expand All @@ -56,20 +65,20 @@ describe(TranslationsService.name, () => {
describe('parseDefaultLanguage', () => {
const languageList = 'en,fr';
it('should fail when using wrong languages format', () => {
const func = (): void => service.initializeTranslations(languageList, 'error');
const func = (): void => service.initializeTranslations(languageList, undefined, 'error');
expect(func).toThrow(`"default-language" expects an ISO 639-1`);
});

it('should display a message when using an unknown languages format', () => {
const infoSpy = jest.spyOn(console, `info`).mockImplementation(() => {});
service.initializeTranslations(languageList, 'zz');
service.initializeTranslations(languageList, undefined, 'zz');

expect(infoSpy).toHaveBeenCalledWith(`No or invalid default language is provided, falling back to en`);
});

it('should find en the translate service as defaultLang', () => {
const expectedLang = 'en';
service.initializeTranslations(languageList, expectedLang);
service.initializeTranslations(languageList, undefined, expectedLang);

expect(translate.defaultLang).toEqual(expectedLang);
});
Expand All @@ -82,7 +91,7 @@ describe(TranslationsService.name, () => {

beforeEach(() => {
translate.setDefaultLang('en');
service.initializeTranslations('en', 'en');
service.initializeTranslations('en', 'en', 'en');
service.handleTranslations(JSON.stringify(infoLinks), '');
});

Expand All @@ -99,7 +108,7 @@ describe(TranslationsService.name, () => {
describe('empty', () => {
it('should not fail', () => {
translate.setDefaultLang('en');
service.initializeTranslations('en', 'en');
service.initializeTranslations('en', 'en', 'en');
const func = (): void => service.handleTranslations('', null);
expect(func).not.toThrow();
});
Expand All @@ -112,7 +121,7 @@ describe(TranslationsService.name, () => {

beforeEach(() => {
translate.setDefaultLang('en');
service.initializeTranslations('en', 'en');
service.initializeTranslations('en', 'en', 'en');
service.handleTranslations('', JSON.stringify(profileLinks));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ import {ObILink} from './service-navigation-web-component.model';
export class TranslationsService {
readonly languageChange$: Observable<string>;
private readonly translate = inject(TranslateService);
private parsedLanguages: string[];
private parsedDefaultLanguage: string;

constructor() {
this.languageChange$ = this.translate.onLangChange.pipe(map(event => event.lang));
}

initializeTranslations(languageList: string, defaultLanguage: string | undefined): void {
const languages = this.parseLanguages(languageList);
const parsedDefaultLanguage = this.parseDefaultLanguage(defaultLanguage, languages);
this.registerLanguagesAndTranslations(languages, parsedDefaultLanguage);
initializeTranslations(languageList: string, language: string | undefined, defaultLanguage: string | undefined): void {
this.parsedLanguages = this.parseLanguages(languageList);
this.parsedDefaultLanguage = this.parseDefaultLanguage(defaultLanguage, this.parsedLanguages);
const parsedLanguage = this.parseLanguage(language, this.parsedDefaultLanguage, this.parsedLanguages);

this.registerLanguagesAndTranslations(this.parsedLanguages, this.parsedDefaultLanguage, parsedLanguage);
}

handleTranslations(infoLinks: string, profileLinks: string): void {
Expand All @@ -31,6 +35,13 @@ export class TranslationsService {
});
}

setLang(lang: string): void {
if (this.parsedLanguages && this.parsedDefaultLanguage) {
const newLang = this.parseLanguage(lang, this.parsedDefaultLanguage, this.parsedLanguages);
this.translate.use(newLang);
}
}

private parseLanguages(languageList: string): string[] {
if (!languageList || !/^[a-z]{2}(?:,[a-z]{2})*$/.test(languageList)) {
throw new Error(
Expand All @@ -41,9 +52,8 @@ export class TranslationsService {
}

private parseDefaultLanguage(defaultLanguage: string | undefined, languages: string[]): string {
if (defaultLanguage && !/^[a-z]{2}$/.test(defaultLanguage)) {
throw new Error(`"default-language" expects an ISO 639-1 language (e.g. en) but received "${defaultLanguage}"`);
}
this.checkLanguageFormat(defaultLanguage, 'default-language');

if (!languages.includes(defaultLanguage)) {
const language = languages[0];
console.info(`No or invalid default language is provided, falling back to ${language}`);
Expand All @@ -52,13 +62,29 @@ export class TranslationsService {
return defaultLanguage;
}

private registerLanguagesAndTranslations(languages: string[], defaultLanguage: string): void {
private parseLanguage(language: string | undefined, defaultLanguage: string, languages: string[]): string {
this.checkLanguageFormat(language, 'language');

if (!languages.includes(language)) {
console.info(`Invalid language is provided, falling back to ${defaultLanguage}`);
return defaultLanguage;
}
return language;
}

private checkLanguageFormat(language: string | undefined, label: 'default-language' | 'language'): void {
if (language && !/^[a-z]{2}$/.test(language)) {
throw new Error(`"${label}" expects an ISO 639-1 language (e.g. en) but received "${language}"`);
}
}

private registerLanguagesAndTranslations(languages: string[], defaultLanguage: string, language: string): void {
this.translate.addLangs(languages);
languages.forEach(language => {
this.translate.setTranslation(language, this.getObliqueTranslations(language), true);
languages.forEach(lang => {
this.translate.setTranslation(lang, this.getObliqueTranslations(lang), true);
});
this.translate.setDefaultLang(defaultLanguage);
this.translate.use(defaultLanguage);
this.translate.use(language);
}

private getObliqueTranslations(language: string): Record<any, string> {
Expand Down

0 comments on commit cff248d

Please sign in to comment.