Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

translate.get sometimes returns key instead of translation

I am currently working on an angular 12 based web application which uses ngx-translate for internationalization and ASP.NET Core 5 for the backend. After adding a component for a new page to the project including routing and everything, it refused to translate anything I wanted it to translate in the new component and just displayed the translation keys instead. After clearing the browser cache, deleting all temporary files of the project and completely recompiling everything, it now seems to work fine. However, there are still a few strange things going on that I just can't explain. When I add the following line to the ngOnInit() method of my new component, it sometimes works fine but sometimes just returns the translation key instead of the translation:

console.log("TEST: ", this.translate.instant('login.success'));

After taking a look at the documentation, it turns out that the instant() method should only be used after ensuring that the translations have been loaded. Alternatively, the documentation mentions that the get() method can be used instead to avoid this problem. I tried that but it sometimes still returns the translation key instead of the translation. How is that possible and how can I fix this issue?

The app.module.ts imports:

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
...
TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })

The app.component constructor:

constructor(private spinner: NgxSpinnerService, public translate: TranslateService) {
  translate.addLangs(['en', 'de']);
  translate.setDefaultLang('en');

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

The app-routing.module:

const routes: Routes = [
  {
    path: "",
    redirectTo: "/login",
    pathMatch: 'full'
  },
  {
    path: "login",
    component: LoginComponent
  },
  {
    path: "landing",
    component: LandingComponent,
    children: [
      {
        path: "",
        component: LandingContentComponent,
      },
      {
        path: "new-component",
        loadChildren: () =>
          import("./new-component/new-component.module").then(
            (m) => m.NewComponentModule
          ),
      },
      { path: "**", redirectTo: "landing" },
    ]
  },
  { path: "**", component: NotFoundComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

The new component module:

...
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(
    http
  );
}


@NgModule({
  declarations: [
    NewComponentComponent
  ],
  imports: [
    ...

    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: (HttpLoaderFactory),
        deps: [HttpClient]
      },
      extend: true
    })
  ],
})
export class NewComponentModule { }

The new-component.component.ts:

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-new-component',
  templateUrl: './new-component.component.html',
  styleUrls: ['./new-component.component.scss']
})
export class NewComponentComponent implements OnInit {

  constructor(public translate: TranslateService) { }

  ngOnInit(): void {
    this.translate.get('login.success').subscribe((translated: string) => {
      console.log("TEST: ", translated);
    });
  }
}
like image 500
Chris Avatar asked Jan 22 '26 11:01

Chris


1 Answers

That happens because you extend the root translation in the lazy-loaded module, and loading its translation lazily using TranslateHttpLoader.

Since the TranslateHttpLoader is loading the translation async, so it may complete the loading before initializing the component (so you get the translation correctly in this case) or may not, which causes the this.translate.get function to fetch the translation from root keys and returns the key itself on failed.

So, to resolve this issue you have to make sure that the lazy-loaded translations have been loaded properly before trying to get/instant the translation of any keys, and thanks to Angular Resolver, which can be used in similar cases:

The router waits for the data to be resolved before the route is finally activated.

So we can create our own resolver to make sure that the component will not be initialized (since the route will not be activated) until the observable of resolver has been resolved (completed).

On the other hand, thanks to the ngx-translate getTranslation function that returns an observable which emit an object of the translation that loaded with the current loader:

Gets an object of translations for a given language with the current loader and passes it through the compiler

So the resolver will look like the following:

@Injectable({ providedIn: 'root' })
export class TranslationResolverService implements Resolve<any> {
  constructor(private translateService: TranslateService) {}

  resolve(): Observable<any> {
    return this.translateService.getTranslation(
      this.translateService.currentLang
    );
  }
}

And you can include it within the NewComponentModule routes under resolve like the following:

const routes: Routes = [
  {
    path: '',
    resolve: [TranslationResolverService],
    component: NewComponentComponent,
    children: [
      // .....
    ],
  },
];
like image 159
Amer Avatar answered Jan 24 '26 19:01

Amer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!