Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ocombe committed May 24, 2017
2 parents b430c71 + d84c69b commit 647c2d7
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 1 deletion.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ examples
coverage
!*.metadata.json
!bundles/*.js
tsconfig.json

#################
## JetBrains
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ import {BrowserModule} from '@angular/platform-browser';
import {HttpModule, Http} from '@angular/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {AppComponent} from "./app";
import {AppComponent} from './app';

// AoT requires an exported function for factories
export function HttpLoaderFactory(http: Http) {
Expand Down Expand Up @@ -306,6 +306,7 @@ To render them, simply use the `innerHTML` attribute with the pipe on any elemen
- `addLangs(langs: Array<string>)`: Add new langs to the list
- `getLangs()`: Returns an array of currently available langs
- `get(key: string|Array<string>, interpolateParams?: Object): Observable<string|Object>`: Gets the translated value of a key (or an array of keys) or the key if the value was not found
- `stream(key: string|Array<string>, interpolateParams?: Object): Observable<string|Object>`: Returns a stream of translated values of a key (or an array of keys) or the key if the value was not found. Without any `onLangChange` events this returns the same value as `get` but it will also emit new values whenever the used language changes.
- `instant(key: string|Array<string>, interpolateParams?: Object): string|Object`: Gets the instant translated value of a key (or an array of keys). /!\ This method is **synchronous** and the default file loader is asynchronous. You are responsible for knowing when your translations have been loaded and it is safe to use this method. If you are not sure then you should use the `get` method instead.
- `set(key: string, value: string, lang?: string)`: Sets the translated value of a key
- `reloadLang(lang: string): Observable<string|Object>`: Calls resetLang and retrieves the translations object for the current loader
Expand Down
26 changes: 26 additions & 0 deletions src/translate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {Injectable, EventEmitter, Inject, OpaqueToken} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {Observer} from "rxjs/Observer";
import "rxjs/add/observable/of";
import "rxjs/add/operator/concat";
import "rxjs/add/operator/share";
import "rxjs/add/operator/map";
import "rxjs/add/operator/merge";
import "rxjs/add/operator/switchMap";
import "rxjs/add/operator/toArray";
import "rxjs/add/operator/take";

Expand Down Expand Up @@ -400,6 +402,30 @@ export class TranslateService {
}
}

/**
* Returns a stream of translated values of a key (or an array of keys) which updates
* whenever the language changes.
* @param key
* @param interpolateParams
* @returns {any} A stream of the translated key, or an object of translated keys
*/
public stream(key: string | Array<string>, interpolateParams?: Object): Observable<string | any> {
if(!isDefined(key) || !key.length) {
throw new Error(`Parameter "key" required`);
}

return this
.get(key, interpolateParams)
.concat(this.onLangChange.switchMap((event: LangChangeEvent) => {
const res = this.getParsedResult(event.translations, key, interpolateParams);
if(typeof res.subscribe === "function") {
return res;
} else {
return Observable.of(res);
}
}));
}

/**
* Returns a translation instantly from the internal state of loaded translation.
* All rules regarding the current language, the preferred language of even fallback languages will be used except any promise handling.
Expand Down
86 changes: 86 additions & 0 deletions tests/translate.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {Observable} from "rxjs/Observable";
import {getTestBed, TestBed, fakeAsync, tick} from "@angular/core/testing";

import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/mapTo';
import 'rxjs/add/operator/zip';

let translations: any = {"TEST": "This is a test"};
class FakeLoader implements TranslateLoader {
Expand Down Expand Up @@ -195,6 +197,90 @@ describe('TranslateService', () => {
});
});

it('should be able to stream a translation for the current language', (done: Function) => {
translations = {"TEST": "This is a test"};
translate.use('en');

translate.stream('TEST').subscribe((res: string) => {
expect(res).toEqual('This is a test');
done();
});
});

it('should be able to stream a translation of an array for the current language', (done: Function) => {
let tr = {"TEST": "This is a test", "TEST2": "This is a test2"};
translate.setTranslation('en', tr);
translate.use('en');

translate.stream(['TEST', 'TEST2']).subscribe((res: any) => {
expect(res).toEqual(tr);
done();
});
});

it('should initially return the same value for streaming and non-streaming get', (done: Function) => {
translations = {"TEST": "This is a test"};
translate.use('en');

translate.stream('TEST').zip(translate.get('TEST')).subscribe((value: [string, string]) => {
const [streamed, nonStreamed] = value;
expect(streamed).toEqual('This is a test');
expect(streamed).toEqual(nonStreamed);
done();
});
});

it('should update streaming translations on language change', (done: Function) => {
translations = {"TEST": "This is a test"};
translate.use('en');

translate.stream('TEST').take(3).toArray().subscribe((res: string[]) => {
const expected = ['This is a test', 'Dit is een test', 'This is a test'];
expect(res).toEqual(expected);
done();
});

translate.setTranslation('nl', {"TEST": "Dit is een test"});
translate.use('nl');
translate.use('en');
});

it('should update streaming translations of an array on language change', (done: Function) => {
const en = {"TEST": "This is a test", "TEST2": "This is a test2"};
const nl = {"TEST": "Dit is een test", "TEST2": "Dit is een test2"};
translate.setTranslation('en', en);
translate.use('en');

translate.stream(['TEST', 'TEST2']).take(3).toArray().subscribe((res: any[]) => {
const expected = [en, nl, en];
expect(res).toEqual(expected);
done();
});

translate.setTranslation('nl', nl);
translate.use('nl');
translate.use('en');
});

it('should interpolate the same param into each streamed value', (done: Function) => {
translations = {"TEST": "This is a test {{param}}"};
translate.use('en');

translate.stream('TEST', { param: 'with param' }).take(3).toArray().subscribe((res: string[]) => {
const expected = [
'This is a test with param',
'Dit is een test with param',
'This is a test with param'
];
expect(res).toEqual(expected);
done();
});

translate.setTranslation('nl', {"TEST": "Dit is een test {{param}}"});
translate.use('nl');
translate.use('en');
});

it('should be able to get instant translations', () => {
translate.setTranslation('en', {"TEST": "This is a test"});
translate.use('en');
Expand Down

0 comments on commit 647c2d7

Please sign in to comment.