transloco icon indicating copy to clipboard operation
transloco copied to clipboard

Bug(transloco): Missing translation error in lazy-loaded pages on initial load

Open ali-memar opened this issue 1 year ago • 8 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Which Transloco package(s) are the source of the bug?

Transloco

Is this a regression?

No

Current behavior

I'm experiencing an issue with Transloco in my Angular project. In a lazy-loaded page, after refreshing, a "Missing translation for 'home'" error appears in the console on the initial load. However, when I navigate to another page and then return to the lazy-loaded page, the error no longer appears.

It seems that on the initial load, the translation file doesn’t load in time, causing the page to render before translations are available.

Steps to Reproduce: 1- Open the lazy-loaded page. 2- Refresh the page. 3- Observe the console for the "Missing translation" error. 4- Navigate to a different page. 5- Return to the lazy-loaded page. 6- Notice that the error is no longer present.

Expected behavior

When navigating to a lazy-loaded page, all required translation files should be fully loaded before the page renders, so that no "Missing translation" errors appear in the console. The page should display all translations correctly, even on the initial load after a refresh.

Please provide a link to a minimal reproduction of the bug, if you won't provide a link the issue won't be handled.

https://codesandbox.io/p/sandbox/vibrant-water-flm8df?workspaceId=c3977a48-d7c1-411a-83ed-053355f0c600

Transloco Config

No response

Please provide the environment you discovered this bug in

"@jsverse/transloco": "7.4.2"

Browser

No response

Additional context

No response

I would like to make a pull request for this bug

No

ali-memar avatar Nov 02 '24 11:11 ali-memar

Is there an existing issue for this?

  • [x] I have searched the existing issues

Which Transloco package(s) are the source of the bug?

Transloco

Is this a regression?

No

Current behavior

I'm experiencing an issue with Transloco in my Angular project. In a lazy-loaded page, after refreshing, a "Missing translation for 'home'" error appears in the console on the initial load. However, when I navigate to another page and then return to the lazy-loaded page, the error no longer appears.

It seems that on the initial load, the translation file doesn’t load in time, causing the page to render before translations are available.

Steps to Reproduce: 1- Open the lazy-loaded page. 2- Refresh the page. 3- Observe the console for the "Missing translation" error. 4- Navigate to a different page. 5- Return to the lazy-loaded page. 6- Notice that the error is no longer present.

Expected behavior

When navigating to a lazy-loaded page, all required translation files should be fully loaded before the page renders, so that no "Missing translation" errors appear in the console. The page should display all translations correctly, even on the initial load after a refresh.

Please provide a link to a minimal reproduction of the bug, if you won't provide a link the issue won't be handled.

https://codesandbox.io/p/sandbox/vibrant-water-flm8df?workspaceId=c3977a48-d7c1-411a-83ed-053355f0c600

Transloco Config

No response

Please provide the environment you discovered this bug in

"@jsverse/transloco": "7.4.2"

Browser

No response

Additional context

No response

I would like to make a pull request for this bug

No

Yes, I am experiencing the same issue. When using Transloco in an Angular project, specifically on a lazy-loaded page, refreshing the page results in a "Missing translation for 'key'" error in the console. However, the issue resolves itself when navigating to another page and then returning to the lazy-loaded page.

aminhavasi avatar Nov 26 '24 05:11 aminhavasi

is there any solution for it??

aminhavasi avatar Nov 26 '24 05:11 aminhavasi

I tried to find a workaround for this and added this code to my app configuration, which helped me solve the problem :

    {
      provide: APP_INITIALIZER,
      useFactory: (translocoService: TranslocoService) => () => {
        // this line to make sure to load translations on first load and avoid missing trads
        // https://github.com/jsverse/transloco/issues/811
        lastValueFrom(translocoService.selectTranslate('app.title')).then();
      },
      deps: [TranslocoService],
      multi: true,
    },

medbenmakhlouf avatar Nov 28 '24 09:11 medbenmakhlouf

I applied this approach to preload the general application language file.

{
      provide: APP_INITIALIZER,
      multi: true,
      useFactory: (translocoService: TranslocoService) => {
        return async () => {
          await translocoService.load('fa').toPromise();
        };
      },
      deps: [TranslocoService],
    },
    

The problem is related to lazy loading translation files. Here's an example configuration I am using with Transloco for lazy loading a route:

{
  path: "lazy",
  loadComponent: () =>
    import("./lazy.component").then((LazyComponent) => LazyComponent),
  providers: [provideTranslocoScope("users")],
}

In the HTML file, translations work perfectly when using the pipe. However, in the TypeScript file, when I use the TranslocoService to fetch translations, the keys are not translated.

HTML example (this works fine):

<h1>{{ 'users.title' | transloco }}</h1>

TypeScript example (this has an issue):

this.translocoService.translate('users.title'); // Returns the key 'title', not the translated value

It seems that when using TranslocoService in lazy-loaded components, the translation files have not been fully loaded yet, resulting in untranslated keys in TypeScript.

Is there any specific configuration or method to ensure that translation files are fully loaded before using the TranslocoService? Or do I need an async approach to fetch translations when working in TypeScript?

saeidi-dev avatar Dec 10 '24 13:12 saeidi-dev

Problem is that APP_INITIALIZER is deprecated and provideAppInitializer should be used instead. Not sure yet how to adjust the app.config to use it so translations would be loaded before guards.

Update: that's how we solved this (we use only single translation file per language, not separating by lazy-loaded components)

// Need to force preload of translations before the app starts (because they are used even in some guards)
makeEnvironmentProviders([
    provideTranslocoLoader(TranslocoHttpLoader),
    provideAppInitializer(() => firstValueFrom(inject(TranslocoService).load(DEFAULT_SYSTEM_LANGUAGE_SPECIFIC_CULTURE))),
]),

liesahead avatar Dec 19 '24 07:12 liesahead

The issue I'm facing with provideTranslocoScope is that while it works fine in the HTML when using the Transloco pipe (translations are correctly applied), in the TypeScript files, when I use the TranslocoService to fetch translations, they are not recognized after the lazy-loaded module.

In other words, the translations are available in the HTML, but not in TypeScript after the module is loaded using the scope provided in the route.

Do you have any suggestions for how I can make sure the translations are accessible in TypeScript when using provideTranslocoScope in lazy-loaded routes?

Everything in my project works correctly, except in cases where I use the provideTranslocoScope provider, I encounter an issue.

I expect this to work:

{
  path: "lazy",
  loadComponent: () =>
    import("./lazy.component").then((LazyComponent) => LazyComponent),
  providers: [
    provideTranslocoScope("users"),
  ],
}

But should it be resolved with a Resolver instead?

{
  path: 'lazy',
  loadComponent: () =>
    import('./lazy.component').then((LazyComponent) => LazyComponent),
  resolve: {
    translations: TranslationResolver,
  },
}


@Injectable({
  providedIn: 'root',
})
export class TranslationResolver implements Resolve<any> {
  constructor(private translocoService: TranslocoService) {}

  resolve() {
    return this.translocoService.load('users').toPromise();
  }
}

saeidi-dev avatar Dec 19 '24 08:12 saeidi-dev

Same issue, any solutions ?

simon-knu avatar Jan 14 '25 16:01 simon-knu

happened for me, mainly when I was using declarative code with signals. I think the signals execute their first computation too soon in the component lifecycle. (the signals do not have a bug, and I think there is no bug in transloco either)

issue (simplified example):

protected readonly someComputedTranslation = computed<SomeDto>(() => {
  const userName = this.userNameSignal(); 
  return {
    label: this.transloco.translate('username'),
    value: userName,
  };
});

solution:

import { toSignal } from '@angular/core/rxjs-interop';

private readonly usernameTranslation = toSignal(this.transloco.selectTranslate<string>('username'));

protected readonly someComputedTranslation = computed<SomeDto>(() => {
  const userName = this.userNameSignal(); 
  const userNameTranslation = this.usernameTranslation();

  // translation not available yet
  if (!userNameTranslation) return { label: 'user name', value: userName }

  return {
    label: userNameTranslation,
    value: userName,
  };
});

my use case was larger, and I didnt want alot of signals for each translation, so I combined them with rxjs forkJoin and used strongly typed strings.

import { forkJoin } from 'rxjs';

private readonly translations = toSignal(
    forkJoin({
      'first-label': this.transloco.selectTranslate<string>('first-label'),
      'second-label': this.transloco.selectTranslate<string>('second-label'),
      'third-label': this.transloco.selectTranslate<string>('third-label'),
    }),
  );

// usage
protected readonly firstLabel = computed<string>(() => this.translations()['first-label']);

RobinMeow avatar May 16 '25 06:05 RobinMeow