Skip to content

Commit

Permalink
#1 add support for translation override
Browse files Browse the repository at this point in the history
  • Loading branch information
syjer committed Jul 7, 2019
1 parent 48f8a9f commit 00c394f
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 38 deletions.
3 changes: 2 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import { I18nService } from './shared/i18n.service';
import { Router } from '@angular/router';

@Component({
selector: 'app-root',
Expand All @@ -11,7 +12,7 @@ export class AppComponent implements OnDestroy {

private langChangeSub : Subscription;

constructor(translate: TranslateService, i18nService: I18nService) {
constructor(translate: TranslateService, i18nService: I18nService, private router: Router) {
translate.setDefaultLang('en');

this.langChangeSub = translate.onLangChange.subscribe(langChange => {
Expand Down
6 changes: 4 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { InvoiceFormComponent } from './reservation/invoice-form/invoice-form.co
import { InvalidFeedbackDirective } from './shared/invalid-feedback.directive';
import { AdditionalServiceComponent } from './additional-service/additional-service.component';
import { RecaptchaComponent } from './recaptcha/recaptcha.component';
import { CustomLoader } from './shared/i18n.service';



Expand Down Expand Up @@ -93,8 +94,9 @@ export function HttpLoaderFactory(http: HttpClient) {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
useClass: CustomLoader,
/*useFactory: HttpLoaderFactory,
deps: [HttpClient]*/
}
}),
NgbTooltipModule
Expand Down
8 changes: 5 additions & 3 deletions src/app/language-selector/language-selector.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, Input } from '@angular/core';
import { Language } from '../model/event';
import { TranslateService } from '@ngx-translate/core';
import { Router } from '@angular/router';
import { I18nService } from '../shared/i18n.service';

@Component({
selector: 'app-language-selector',
Expand All @@ -12,9 +13,10 @@ export class LanguageSelectorComponent {
@Input()
contentLanguages: Language[];

constructor(private translate: TranslateService) { }
constructor(private i18nService: I18nService, private router: Router) { }

public changeLanguage(lang: string): void {
this.translate.use(lang);
const eventShortName = this.router.routerState.snapshot.root.firstChild ? this.router.routerState.snapshot.root.firstChild.params['eventShortName'] : null;
this.i18nService.useTranslation(eventShortName, lang).subscribe(r => {});
}
}
46 changes: 18 additions & 28 deletions src/app/language.guard.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,58 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { I18nService } from './shared/i18n.service';
import { Observable, of, zip } from 'rxjs';
import { I18nService, CustomLoader } from './shared/i18n.service';
import { EventService } from './shared/event.service';
import { TranslateService } from '@ngx-translate/core';
import { map, publishReplay, refCount } from 'rxjs/operators';
import { map, mergeMap, switchMap } from 'rxjs/operators';

@Injectable({
providedIn: 'root'
})
export class LanguageGuard implements CanActivate {

//
private applicationLanguages: Observable<string[]>;
private eventLanguages: {[name:string]: Observable<string[]>} = {};

//

constructor(private i18nService: I18nService, private eventService: EventService, private translate: TranslateService) {
constructor(private i18nService: I18nService, private eventService: EventService, private translate: TranslateService, private customLoader: CustomLoader) {
}

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

const persisted = this.i18nService.getPersistedLanguage();

//set before calling, to avoid any strange flashes
if (persisted) {
if (persisted && this.translate.currentLang != persisted) {
this.translate.use(persisted);
}

const eventShortName = next.params['eventShortName'];
const req = eventShortName ? this.getForEvent(eventShortName) : this.getForApp();

return req.pipe(map(availableLanguages => {
this.useLanguage(availableLanguages, persisted);
return true;
}));
return req.pipe(switchMap(availableLanguages => {
const lang = this.extractLang(availableLanguages, persisted);
return this.i18nService.useTranslation(eventShortName, lang);
}))
}

private getForEvent(eventShortName: string): Observable<string[]> {

if (!this.eventLanguages[eventShortName]) {
this.eventLanguages[eventShortName] = this.eventService.getAvailableLanguageForEvent(eventShortName).pipe(publishReplay(1), refCount())
}

return this.eventLanguages[eventShortName];
return this.eventService.getAvailableLanguageForEvent(eventShortName);
}

private getForApp(): Observable<string[]> {

if (!this.applicationLanguages) {
this.applicationLanguages = this.i18nService.getAvailableLanguages().pipe(map(languages => languages.map(l => l.locale)), publishReplay(1), refCount());
}

return this.applicationLanguages;
return this.i18nService.getAvailableLanguages().pipe(map(languages => languages.map(l => l.locale)));
}

private useLanguage(availableLanguages: string[], persisted: string): void {
private extractLang(availableLanguages: string[], persisted: string): string {
var lang;
if (availableLanguages.indexOf(persisted) >= 0) {
this.translate.use(persisted);
lang = persisted;
} else if (availableLanguages.indexOf(this.translate.getBrowserLang()) >= 0) {
this.translate.use(this.translate.getBrowserLang());
lang = this.translate.getBrowserLang();
} else {
this.translate.use(availableLanguages[0]);
lang = availableLanguages[0];
}
return lang;
}

}
45 changes: 41 additions & 4 deletions src/app/shared/i18n.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { Injectable } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { Observable } from 'rxjs';
import { Observable, of, zip } from 'rxjs';
import { Language } from '../model/event';
import { LocalizedCountry } from '../model/localized-country';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { TranslateService, TranslateLoader } from '@ngx-translate/core';
import { Router, NavigationStart } from '@angular/router';
import { publishReplay, refCount, map, mergeMap } from 'rxjs/operators';
import { EventService } from './event.service';

@Injectable({
providedIn: 'root'
})
export class I18nService {

constructor(private http: HttpClient, private title: Title, private translateService: TranslateService, private router: Router) { }

private applicationLanguages: Observable<Language[]>;

constructor(private http: HttpClient, private title: Title, private translateService: TranslateService, private router: Router, private customLoader: CustomLoader, private eventService: EventService) { }

getCountries(locale: string): Observable<LocalizedCountry[]> {
return this.http.get<LocalizedCountry[]>(`/api/v2/public/i18n/countries/${locale}`);
Expand All @@ -27,7 +32,10 @@ export class I18nService {
}

getAvailableLanguages(): Observable<Language[]> {
return this.http.get<Language[]>(`/api/v2/public/i18n/languages`);
if(!this.applicationLanguages) {
this.applicationLanguages = this.http.get<Language[]>(`/api/v2/public/i18n/languages`).pipe(publishReplay(1), refCount());
}
return this.applicationLanguages;
}

setPageTitle(titleCode: string, eventName: string): void {
Expand Down Expand Up @@ -58,4 +66,33 @@ export class I18nService {
getCurrentLang(): string {
return this.translateService.currentLang;
}

useTranslation(eventShortName: string, lang: string) : Observable<boolean> {
const overrideBundle = eventShortName ? this.eventService.getEvent(eventShortName).pipe(map(e => e.i18nOverride[lang] || {})) : of({});
return zip(this.customLoader.getTranslation(lang), overrideBundle).pipe(mergeMap(([root, override]) => {
console.log('setting translations for lang:', lang);
console.log('root bundle is:', root);
console.log('override bundle is:', override);
this.translateService.setTranslation(lang, root, false);
this.translateService.setTranslation(lang, override, true);
this.translateService.use(lang);
return of(true);
}));
}
}

const translationCache: {[key:string]: Observable<any>} = {};

@Injectable({providedIn: 'root'})
export class CustomLoader implements TranslateLoader {

constructor(private http: HttpClient) {
}

getTranslation(lang: string): Observable<any> {
if (!translationCache[lang]) {
translationCache[lang] = this.http.get(`/api/v2/public/i18n/bundle/${lang}`).pipe(publishReplay(1), refCount());
}
return translationCache[lang];
}
}

0 comments on commit 00c394f

Please sign in to comment.