Use @ngx-translate in standalone components in Angular 17
Asked Answered
Q

2

14

I use standalone components in Angular 17. When I used module architecture, I didn't have this problem. I added it to import in AppModule and it works good.

imports: [
 TranslateModule.forRoot(loader)
],

But if I add TranslateModule.forRoot(loader) in standalone components

@Component({
 selector: 'app-main-work-space',
 standalone: true,
 imports: [
  // @ts-ignore
  TranslateModule.forRoot(loader)
 ],
 templateUrl: './main-work-space.component.html',
 styleUrl: './main-work-space.component.scss'
})

In result I have this mistake.

✘ [ERROR] TS-992012: 'imports' contains a ModuleWithProviders value, likely the result of a 'Module.forRoot()'-style call. These calls are not used to configure components and are not valid in standalone component imports - consider importing them in the application bootstrap instead.

I try add @ts-ignore but it doesn't help.

How can I fix it?

Quail answered 4/1 at 18:40 Comment(9)
Is your whole application standalone (you're bootstrapping a standalone component) or is your application still module based (you have a root NgModule)?Mg
You only want to use SomeModule.forRoot() once in your application (in the imports of a root NgModule when calling .bootstrapModule() in main.ts). Some packages have a SomeModule.forChild() method that can be used to import the package in a child NgModule.Mg
If you're using a fully standalone application, you have access to .bootstrapApplication() and its ApplicationConfiguration in which you can specify providers as if there were a root NgModule. There are cleaner ways if the package supports them, but calling SomeModule.forRoot() here is supported.Mg
How can I add ` TranslateModule.forRoot(loader)` to ApplicationConfigQuail
You use .importProvidersFrom() like so: .bootstrapApplication(AppComponent, { providers: [ importProvidersFrom(TranslateModule.forRoot(loader)) ] });.Mg
I did it but have the mistake in html in /main-work-space.component.html. translate pipe is red and it proposes add TranslateModule to import in MainWorkSpaceComponentQuail
You can just imports: [TranslateModule] in your component. There's no need to call .forRoot() there. This is the same thing you would do if importing into an AppModule (where you call .forRoot()) and a SharedModule (where you don't call .forRoot()).Mg
In result I have this main.ts:5 ERROR NullInjectorError: R3InjectorError(Standalone[_AppComponent])[_TranslateService -> _TranslateService -> _TranslateService]:Quail
I'm not sure what the transitive dependencies here are. That looks like there should be something else in the call to .forRoot() when bootstrapping the application. If TranslateModule.forRoot() doesn't return a provider for TranslateService, you might have to add one on your own: providers: [TranslateModule.forRoot(loader), { provide: TranslateService, useFactory/useClass/useExisting: ... }]. That's falling into configuration of @ngx-translate, though.Mg
R
25

I think you missed the importProvidersFrom wrapper for translation module, please find below working example along with extra sample code, to help you resolve your problem!

import { Component, importProvidersFrom } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
import { provideHttpClient } from '@angular/common/http';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppModule } from './app/app.module';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import 'zone.js';

// AoT requires an exported function for factories
export function HttpLoaderFactory(httpClient: HttpClient) {
  return new TranslateHttpLoader(httpClient);
}

@Component({
  selector: 'app-root',
  imports: [CommonModule, TranslateModule],
  standalone: true,
  template: `
    <div>
      <h2>{{ 'HOME.TITLE' | translate }}</h2>
      <label>
        {{ 'HOME.SELECT' | translate }}
        <select #langSelect (change)="translate.use(langSelect.value)">
          <option *ngFor="let lang of translate.getLangs()" [value]="lang" [selected]="lang === translate.currentLang">{{ lang }}</option>
        </select>
      </label>
    </div>
  `,
})
export class AppComponent {
  constructor(public translate: TranslateService) {
    translate.addLangs(['en', 'fr']);
    translate.setDefaultLang('en');

    const browserLang = translate.getBrowserLang();
    translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');
  }
}

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(),
    importProvidersFrom(
      TranslateModule.forRoot({
        loader: {
          provide: TranslateLoader,
          useFactory: HttpLoaderFactory,
          deps: [HttpClient],
        },
      })
    ),
  ],
});

stackblitz

Stackblitz for reference not by me

Rocketry answered 5/1 at 7:9 Comment(1)
thank you, this has been giving me such a headachePuerperal
Z
2
//app.config.ts
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideAnimations } from '@angular/platform-browser/animations';
import { HttpBackend, HttpClient, HttpClientModule, provideHttpClient } from '@angular/common/http';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

export const provideTranslation = () => ({
  defaultLanguage: 'en',
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,
    deps: [HttpClient],
  },
});

export function HttpLoaderFactory(http: HttpClient) {
  return  new  TranslateHttpLoader(http, './assets/i18n/', '.json');
}
export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes),provideAnimations(),provideHttpClient(),importProvidersFrom(HttpClientModule), importProvidersFrom([TranslateModule.forRoot(provideTranslation())
  ]),],
};
//particular compo
import { TranslateModule, TranslateService } from '@ngx-translate/core';
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [TranslateModule]
})constructor(
   public translate: TranslateService
  ) {}

this.translate.setDefaultLang('en'); //ngonint
Zehe answered 22/4 at 13:35 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Mays

© 2022 - 2024 — McMap. All rights reserved.