Skip to content

Commit

Permalink
chore(TranslateModule): renamed useStore to isolate, and updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ocombe committed Feb 3, 2017
1 parent b626c0e commit d3f376b
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 51 deletions.
68 changes: 47 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ If you're importing directly from `node_modules`, you should edit your systemjs

#### 1. Import the `TranslateModule`:

Finally, you can use ngx-translate in your Angular project. It is recommended to import `TranslateModule.forRoot()` in the NgModule of your application.
Finally, you can use ngx-translate in your Angular project. You have to import `TranslateModule.forRoot()` in the root NgModule of your application.

The [`forRoot`](https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root) static method is a convention that provides and configures services at the same time. Make sure you only call this method at the root module of your application, most of the time called `AppModule`. This method allows you to configure the `TranslateModule` loader. By default it will use the `TranslateStaticLoader`, but you can provide another loader instead as a parameter of this method (see below [Write & use your own loader](#write--use-your-own-loader)).
The [`forRoot`](https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root) static method is a convention that provides and configures services at the same time.
Make sure you only call this method in the root module of your application, most of the time called `AppModule`.
This method allows you to configure the `TranslateModule` by specifying a loader, a parser and/or a missing translations handler.

```ts
import {BrowserModule} from '@angular/platform-browser';
Expand All @@ -51,7 +53,8 @@ export class AppModule { }

##### SharedModule

If you use a [`SharedModule`](https://angular.io/docs/ts/latest/guide/ngmodule.html#!#shared-modules) that you import in multiple other feature modules, you can easily export the `TranslateModule` to make sure you don't have to import it in every module.
If you use a [`SharedModule`](https://angular.io/docs/ts/latest/guide/ngmodule.html#!#shared-modules) that you import in multiple other feature modules,
you can export the `TranslateModule` to make sure you don't have to import it in every module.

```ts
@NgModule({
Expand All @@ -63,7 +66,29 @@ If you use a [`SharedModule`](https://angular.io/docs/ts/latest/guide/ngmodule.h
export class SharedModule { }
```

> Note: Never call a `forRoot` static method in the `SharedModule`. You will end up with multiple different instances of a service in your injector tree.
> Note: Never call a `forRoot` static method in the `SharedModule`. You might end up with different instances of the service in your injector tree. But you can use `forChild` if necessary.
##### Lazy loaded modules

When you lazy load a module, you should use the `forChild` static method to import the `TranslateModule`.

Since lazy loaded modules use a different injector from the rest of your application, you can configure them separately with a different loader/parser/missing translations handler.
You can also isolate the service by using `isolate: true`. In which case the service is a completely isolated instance (for translations, current lang, events, ...).
Otherwise, by default, it will share its data with other instances of the service (but you can still use a different loader/parser/handler even if you don't isolate the service).

```ts
@NgModule({
imports: [
TranslateModule.forChild({
loader: {provide: TranslateLoader, useClass: CustomLoader},
parser: {provide: TranslateParser, useClass: CustomParser},
missingTranslationHandler: {provide: MissingTranslationHandler, useClass: CustomHandler},
isolate: true
})
]
})
export class LazyLoadedModule { }
```

##### Configuration

Expand Down Expand Up @@ -93,9 +118,11 @@ export function HttpLoaderFactory(http: Http) {
BrowserModule,
HttpModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
}
})
],
bootstrap: [AppComponent]
Expand All @@ -109,17 +136,19 @@ If you want to configure a custom `TranslateLoader` while using [AoT compilation

```ts
export function createTranslateLoader(http: Http) {
return new TranslateStaticLoader(http, './assets/i18n', '.json');
return new TranslateHttpLoader(http, './assets/i18n', '.json');
}

@NgModule({
imports: [
BrowserModule,
HttpModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [Http]
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [Http]
}
})
],
bootstrap: [AppComponent]
Expand Down Expand Up @@ -154,7 +183,7 @@ export class AppComponent {

#### 3. Define the translations:

Once you've imported the `TranslateModule`, you can put your translations in a json file that will be imported with the `TranslateStaticLoader`. The following translations should be stored in `en.json`.
Once you've imported the `TranslateModule`, you can put your translations in a json file that will be imported with the `TranslateHttpLoader`. The following translations should be stored in `en.json`.

```json
{
Expand Down Expand Up @@ -303,8 +332,7 @@ Once you've defined your loader, you can provide it in your configuration by add
imports: [
BrowserModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useClass: CustomLoader
loader: {provide: TranslateLoader, useClass: CustomLoader}
})
],
bootstrap: [AppComponent]
Expand All @@ -330,16 +358,18 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler {
}
```

Setup the Missing Translation Handler in your module by adding it to the `providers` list.
Setup the Missing Translation Handler in your module import by adding it to the `forRoot` (or `forChild`) configuration.

```ts
@NgModule({
imports: [
BrowserModule,
TranslateModule.forRoot()
TranslateModule.forRoot({
missingTranslationHandler: {provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler}
})
],
providers: [
{ provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler }
],
bootstrap: [AppComponent]
})
Expand All @@ -359,10 +389,6 @@ If you need it for some reason, you can use the `TranslateParser` service.

## FAQ

#### I'm getting an error `No provider for Http!`

Because of the TranslateStaticLoader you have to load the HttpModule from `@angular/http`, even if you don't use this Loader

#### I'm still using Angular with beta / RC / 2.0 to 2.2, but I cannot use ngx-translate because I get errors?!

I'm sorry but ngx-translate only supports Angular from version 2.3.0 and above because of changes in the framework...
Expand Down
8 changes: 4 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {TranslateDirective} from "./src/translate.directive";
import {TranslatePipe} from "./src/translate.pipe";
import {TranslateStore} from "./src/translate.store";
import {USE_STORE} from "./src/translate.service";
import {isDefined} from "./src/util";

export * from "./src/translate.loader";
export * from "./src/translate.service";
Expand All @@ -20,7 +19,8 @@ export interface TranslateModuleConfig {
loader?: Provider;
parser?: Provider;
missingTranslationHandler?: Provider;
useStore?: boolean;
// isolate the service instance, only works for lazy loaded modules or components with the "providers" property
isolate?: boolean;
}

@NgModule({
Expand All @@ -47,7 +47,7 @@ export class TranslateModule {
config.parser || {provide: TranslateParser, useClass: TranslateDefaultParser},
config.missingTranslationHandler || {provide: MissingTranslationHandler, useClass: FakeMissingTranslationHandler},
TranslateStore,
{provide: USE_STORE, useValue: isDefined(config.useStore) ? config.useStore : true},
{provide: USE_STORE, useValue: config.isolate},
TranslateService
]
};
Expand All @@ -65,7 +65,7 @@ export class TranslateModule {
config.loader || {provide: TranslateLoader, useClass: TranslateFakeLoader},
config.parser || {provide: TranslateParser, useClass: TranslateDefaultParser},
config.missingTranslationHandler || {provide: MissingTranslationHandler, useClass: FakeMissingTranslationHandler},
{provide: USE_STORE, useValue: isDefined(config.useStore) ? config.useStore : true},
{provide: USE_STORE, useValue: config.isolate},
TranslateService
]
};
Expand Down
45 changes: 24 additions & 21 deletions src/translate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class TranslateService {
* @type {EventEmitter<TranslationChangeEvent>}
*/
get onTranslationChange(): EventEmitter<TranslationChangeEvent> {
return this.useStore ? this.store.onTranslationChange : this._onTranslationChange;
return this.isolate ? this._onTranslationChange : this.store.onTranslationChange;
}

/**
Expand All @@ -67,7 +67,7 @@ export class TranslateService {
* @type {EventEmitter<LangChangeEvent>}
*/
get onLangChange(): EventEmitter<LangChangeEvent> {
return this.useStore ? this.store.onLangChange : this._onLangChange;
return this.isolate ? this._onLangChange : this.store.onLangChange;
}

/**
Expand All @@ -78,20 +78,21 @@ export class TranslateService {
* @type {EventEmitter<DefaultLangChangeEvent>}
*/
get onDefaultLangChange() {
return this.useStore ? this.store.onDefaultLangChange : this._onDefaultLangChange;
return this.isolate ? this._onDefaultLangChange : this.store.onDefaultLangChange;
}

/**
* The default lang to fallback when translations are missing on the current lang
*/
get defaultLang(): string {
return this.useStore ? this.store.defaultLang : this._defaultLang;
return this.isolate ? this._defaultLang : this.store.defaultLang;
}

set defaultLang(defaultLang: string) {
if(this.useStore) {
this.store.defaultLang = defaultLang;
} else {
if(this.isolate) {
this._defaultLang = defaultLang;
} else {
this.store.defaultLang = defaultLang;
}
}

Expand All @@ -100,13 +101,14 @@ export class TranslateService {
* @type {string}
*/
get currentLang(): string {
return this.useStore ? this.store.currentLang : this._currentLang;
return this.isolate ? this._currentLang : this.store.currentLang;
}

set currentLang(currentLang: string) {
if(this.useStore) {
this.store.currentLang = currentLang;
} else {
if(this.isolate) {
this._currentLang = currentLang;
} else {
this.store.currentLang = currentLang;
}
}

Expand All @@ -115,13 +117,14 @@ export class TranslateService {
* @type {Array}
*/
get langs(): string[] {
return this.useStore ? this.store.langs : this._langs;
return this.isolate ? this._langs : this.store.langs;
}

set langs(langs: string[]) {
if(this.useStore) {
this.store.langs = langs;
} else {
if(this.isolate) {
this._langs = langs;
} else {
this.store.langs = langs;
}
}

Expand All @@ -130,14 +133,14 @@ export class TranslateService {
* @type {{}}
*/
get translations(): any {
return this.useStore ? this.store.translations : this._translations;
return this.isolate ? this._translations : this.store.translations;
}

set translations(translations: any) {
if(this.useStore) {
this.store.translations = translations;
} else {
if(this.isolate) {
this._currentLang = translations;
} else {
this.store.translations = translations;
}
}

Expand All @@ -147,13 +150,13 @@ export class TranslateService {
* @param currentLoader An instance of the loader currently used
* @param parser An instance of the parser currently used
* @param missingTranslationHandler A handler for missing translations.
* @param useStore whether this service should use the store or not
* @param isolate whether this service should use the store or not
*/
constructor(public store: TranslateStore,
public currentLoader: TranslateLoader,
public parser: TranslateParser,
public missingTranslationHandler: MissingTranslationHandler,
@Inject(USE_STORE) private useStore: boolean = true) {
@Inject(USE_STORE) private isolate: boolean = false) {
}

/**
Expand Down
10 changes: 5 additions & 5 deletions tests/translate.store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ describe("module", () => {
}))
);

it("should create 2 instances of the service when lazy loaded using forChild and useStore false", fakeAsync(inject(
it("should create 2 instances of the service when lazy loaded using forChild and isolate true", fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
let LoadedModule = getLazyLoadedModule(TranslateModule.forChild({useStore: false}));
let LoadedModule = getLazyLoadedModule(TranslateModule.forChild({isolate: true}));
loader.stubbedModules = {expected: LoadedModule};

const fixture = createRoot(router, RootCmp),
Expand All @@ -153,7 +153,7 @@ describe("module", () => {
}))
);

it("should relay events when lazy loading & using forChild with useStore true", fakeAsync(inject(
it("should relay events when lazy loading & using forChild with isolate false", fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
let LoadedModule = getLazyLoadedModule(TranslateModule.forChild());
Expand All @@ -178,10 +178,10 @@ describe("module", () => {
}))
);

it("should not relay events when lazy loading & using forChild with useStore false", fakeAsync(inject(
it("should not relay events when lazy loading & using forChild with isolate true", fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
let LoadedModule = getLazyLoadedModule(TranslateModule.forChild({useStore: false}));
let LoadedModule = getLazyLoadedModule(TranslateModule.forChild({isolate: true}));
loader.stubbedModules = {expected: LoadedModule};

const fixture = createRoot(router, RootCmp),
Expand Down

0 comments on commit d3f376b

Please sign in to comment.