Ngx-translate: pipe not found in custom components


#1

I’m using ngx-translate in a lazy-loading project and it works fine in all my @IonicPage components. I have a shared components.module.ts which I load into each @IonicPage’s module.ts and this is where I can share common components. My problem is that these common components do not have a module.ts of their own so I can’t import components.module.ts to use the ‘translate’ pipe.

My components.module.ts looks like this:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { EventRowComponent } from './event-row/event-row';
import { IonicModule } from "ionic-angular";
import { CollapsableComponent } from './collapsable/collapsable';

@NgModule({
	declarations: [
	  EventRowComponent,
          CollapsableComponent
        ],
	imports:      [ IonicModule ],
	exports:      [
	  TranslateModule,
          EventRowComponent,
          CollapsableComponent
       ],
       schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class ComponentsModule {}

Here, I share EventRowComponent but I can’t get the ‘translate’ pipe to work inside this component since it doesn’t have a module.ts. Kind of a tricky problem.

The start of my EventRowComponent looks like this:

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'event-row',
  templateUrl: 'event-row.html'
})
export class EventRowComponent {

  @Input('event') event;
  @Input('selected') selected;
  @Output() clickHeader = new EventEmitter();

I use this component as follow in an @IonicPage:

<div *ngFor="let event of eventList">
        <event-row [event]="event" [selected]="event === selectedEvent" (clickHeader)="onClickEventHeader(event)"></event-row>
</div>

Anyone know how I can get the ‘translate’ pipe working inside a custom component like this?


#2

I’ve come across this problem and I have a temporary fix for this:

On your custom_component.html
{{ title }}

On your custom_component.ts
@Input(‘title’) textTitle;

ngAfterViewInit(){
this.title = this.textTitle;
}

Then finally, on your page invoke this way:

your_page.html
<custom_component title="{{title | translate}}"></custom_component>

your_page.ts
this.title: String = ‘YOURi18TEXT’;

Pros:
On page load it will have the translated value.

Cons:
Changing language directly on the page will not change the value… So if you can find a fix for importing a component inside a component please let me know.

Update:
If you’re trying to change the language through your custom_component you can reset the value everytime this function is called:

changeLanguage() {
if (this.translate.currentLang == ‘pt-PT’)
this.translate.use(‘en’);
else
this.translate.use(‘pt-PT’);
this.title = this.textTitle;
}

Still just a fix but solves the problem I mentioned before


#3

Any permanent solution


#4

I’ve since switched to Ionic 4 and found a good clean solution.
I’ll try to sum it up:

npm install your packages. In my package.json I currently have:

    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",

In app.module.ts, I have (essentially):

import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouterModule, RouteReuseStrategy, Routes} from '@angular/router';
import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {IonicModule, IonicRouteStrategy} from '@ionic/angular';
import {AppComponent} from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {ComponentsModule} from './components/components.module';
import {PlayerPickerPage} from "./modal/player-picker/player-picker.page";
import {NotifPromptPage} from "./modal/notif-prompt/notif-prompt.page";
import {OkMessagePage} from "./modal/ok-message/ok-message.page";
import {SingleSelectPage} from "./modal/single-select/single-select.page";
import {PlayerPickerPageModule} from "./modal/player-picker/player-picker.module";
import {NotifPromptPageModule} from "./modal/notif-prompt/notif-prompt.module";
import {OkMessagePageModule} from "./modal/ok-message/ok-message.module";
import {SingleSelectPageModule} from "./modal/single-select/single-select.module";
// excluded some other imports not relevant to our conversation

@NgModule({
    declarations: [AppComponent],
    entryComponents: [
        PlayerPickerPage, // Pages I intend to use with popoverController
        NotifPromptPage,
        OkMessagePage,
        SingleSelectPage
    ],
    imports: [
        BrowserModule,
        HttpClientModule,
        AppRoutingModule,
        ComponentsModule, // my shared components module
        IonicModule.forRoot(),
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: (HttpLoaderFactory),
                deps: [HttpClient]
            }
        }),
        IonicStorageModule.forRoot(),

        PlayerPickerPageModule, // Modules of pages I intend to use with popoverController
        NotifPromptPageModule,
        OkMessagePageModule,
        SingleSelectPageModule

    ],
    exports: [],
    providers: [
        StatusBar,
        SplashScreen,
        Device,
        OneSignal,
        InAppBrowser,
        {provide: RouteReuseStrategy, useClass: IonicRouteStrategy}
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    bootstrap: [AppComponent]
})
export class AppModule {
}

export function HttpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

Then I created a module called src/shared/shared.module.ts and this is the only place where I import the translate modules.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [],
  exports: [
    TranslateModule
  ]
})
export class SharedModule { }

Then in any page I need to have the translate pipe working, I simply go in that page’s module.ts and import my Shared Module: for example in my login page

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';

import { IonicModule } from '@ionic/angular';
import { SharedModule } from '../../shared/shared.module'; // allows use of translate pipe
import { LoginPage } from './login.page';

const routes: Routes = [
  {
    path: '',
    component: LoginPage
  }
];

@NgModule({
  imports: [
    CommonModule,
    SharedModule,
    FormsModule,
    IonicModule,
    RouterModule.forChild(routes)
  ],
  declarations: [LoginPage]
})
export class LoginPageModule {}

The tricky part was to get the translate pipe working in common components. Here goes. To create a new component, create an app/components folder and, in that folder, create components.module.ts. This module will import in ever new component you create. So if you create:

 // notice that I specified I want to create it in the "components" folder.
ionic generate component components/MyHeader

(I think that if you simply do the ionic generate component step in a subfolder, it might create the common module automatically.)

Now go look in your components.module.ts and it should have automatically added your components to the declarations. Now to get the translate pipe to work in all these components (since they don’t have a module.ts of their own), import the SharedModule into your components.module.ts. The final result looks like this:

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {IonicModule} from '@ionic/angular';
import {SharedModule} from '../shared/shared.module';

import {TreeNodeComponent} from "./tree-node/tree-node.component";
import {MyHeaderComponent} from './my-header/my-header.component';

@NgModule({
    imports: [
        CommonModule,
        IonicModule,
        SharedModule, // imports translate modules
    ],
    declarations: [
        TreeNodeComponent,
        MyHeaderComponent
    ],
    exports: [
        TreeNodeComponent,
        MyHeaderComponent
    ],
    entryComponents: []
})
export class ComponentsModule {
}

MyHeader should now work with translate pipes. I was already using a component called TreeNodeComponent and the translate pipe works in it.


#5

Ok Will try tomorrow thanks