robisim74 / angular-l10n

Angular library to translate texts, dates and numbers
MIT License
380 stars 59 forks source link

Problems after Upgrading #335

Closed djanesch closed 1 year ago

djanesch commented 2 years ago

I'm submitting a...

[ ] bug report
[ ] feature request
[x] support request

Expected behavior Translation of text Actual behavior Usage of the Keynames Steps to reproduce the behavior I have upgraded an running project from angular v7.2.2 and angular-l10n v7.0.2 to angular v12.2.12 and angular-l10n v12.0.1. After clearing all compiling blockers I can successfully run the application but the translations are not displayed just the keynames.

Previous app.module.ts:

const l10nConfig: L10nConfig = {
  logger: {
    level: environment.production ? LogLevel.Off : LogLevel.Warn
  },
  locale: {
    languages: [{ code: 'de', dir: 'ltr' }, { code: 'en', dir: 'ltr' }, { code: 'it', dir: 'ltr' }],
    defaultLocale: { languageCode: 'de', countryCode: 'AT' },
    currency: 'EUR',
    storage: StorageStrategy.Cookie
  },
  translation: {
    composedKeySeparator: '.',
    providers: [
      { type: ProviderType.Fallback, prefix: './assets/i18n/global', fallbackLanguage: [] },
      { type: ProviderType.Fallback, prefix: './assets/i18n/locale-', fallbackLanguage: [ISOCode.Language] },
      { type: ProviderType.Static, prefix: './assets/i18n/locale-' }
    ],
    composedLanguage: [ISOCode.Language, ISOCode.Country]
  }
};

export function initL10n(injector: Injector, l10nLoader: L10nLoader): Function {
  return () =>
    new Promise(resolve => {
      const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve(null));
      locationInitialized.then(() => {
        l10nLoader.load().then(() => resolve(null));
      });
    });
}

Current app.module.ts (minimal and with Inline-Text just for test purposes):

export const l10nConfig: L10nConfig = {
  format: 'language-region',
  providers: [
      { name: 'app', asset: i18nAsset }
  ],
  cache: true,
  keySeparator: '.',
  defaultLocale: { language: 'de-AT', currency: 'EUR', timeZone: 'Europe/Vienna' },
  schema: [
      { locale: { language: 'de-AT', currency: 'EUR', timeZone: 'Europe/Vienna' }, dir: 'ltr', text: 'Austria' },
      { locale: { language: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' }, dir: 'ltr', text: 'United States' },
      { locale: { language: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' }, dir: 'ltr', text: 'Italia' }
  ],
};

The Login Component:

import { HttpErrorResponse } from '@angular/common/http';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Response, ResponseType } from '@angular/http';
import { MatDialog } from '@angular/material/dialog';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { L10nConfig, L10nLocale, L10nTranslationService, L10N_CONFIG, L10N_LOCALE } from 'angular-l10n';
import { throwError as observableThrowError } from 'rxjs';
import { oase_config } from '../../environments/environment';
import { AuthService } from '../shared/auth.service';
import { LoggerService } from '../shared/logger.service';
import { Httpstatus } from '../shared/response/httpstatus.model';
import { Kernantwort } from '../shared/response/kernantwort.model';
import { SessionService } from '../shared/session.service';

const PATH_FILE = 'app/unprotected/signin.component.ts';

const BACKEND_PATH_PREFIX = 'signin/';

@Component({
  templateUrl: './signin.component.html'
})
export class SigninComponent implements OnInit {
  lang: string;
  isSigninRunning = false;
  signinForm: FormGroup;
  fehler: Kernantwort = null;
  appid_vorhanden = false;
  fehler_keineappid = '';
  appVersion: string = oase_config.appversion;
  @ViewChild('password') password;

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private fb: FormBuilder,
    private authService: AuthService,
    public sessService: SessionService,
    public dialogRef: MatDialog,
    public title: Title,
    @Inject(L10N_LOCALE) public locale: L10nLocale,
    @Inject(L10N_CONFIG) private l10nConfig: L10nConfig,
    public translation: L10nTranslationService,
    private _logger: LoggerService
  ) {
    // Set document title.
    this.title.setTitle(this.getTitle());
    //        this.translation.onChange().subscribe(() => { this.title.setTitle(this.getTitle()); });

    this._logger.log(PATH_FILE + ' - isAuth: ' + this.isAuth());
    if (this.isAuth()) {
      this.router.navigate(['/home']);
    } else {
      // close open dialogs on token expiration
      this.dialogRef.closeAll();
    }
  }

  onSignin() {
    this.isSigninRunning = true;
    this.fehler = null;
    let auth_token: string = null;
    let success = null;

    this._logger.log(PATH_FILE + ' - onSignin vor authService.signinUser');
    this.authService.signinUser(this.signinForm.value).subscribe(
      data => {
        this._logger.log(PATH_FILE + ' - onSignin subscribe data: ', data);
        (auth_token = data.authtoken), (success = data.success);
      },
      err => {
        this._logger.log(PATH_FILE + ' - onSignin subscribe err: ', err);
        this.isSigninRunning = false;
        this.handleError(err, 'Fehler bei Anmeldung');
      },
      () => {
        this._logger.log(PATH_FILE + ' - onSignin subscribe complete');
        // Merken wann der Benutzer sich eingeloggt hat (wird für die Anzeige von neuen Schlüssel benötigt)
        this.authService.storeJwToken(auth_token, new Date().getTime());
        this.authService.logTokenInfos(PATH_FILE + ' - signinUser');
        this.router.navigate(['/home']);
        this.isSigninRunning = false;
      }
    );
  }

  ngOnInit(): any {
    // Set document title.
    this.translation.onChange().subscribe(() => {
      this.title.setTitle(this.getTitle());
    });

    this.activatedRoute.params.subscribe((params: Params) => {
      console.log(PATH_FILE + " - params['appid'] param: " + params['appid']);
      this.appid_vorhanden = oase_config.singlecompany || (params['appid'] != null && params['appid'].length > 0);
      if (!this.appid_vorhanden) {
        this.fehler = new Kernantwort();
        this.fehler.messagehtml = this.translation.translate('login.keine_appid', { url: '/' + BACKEND_PATH_PREFIX });
      }
      console.log(PATH_FILE + " - params['appid']: " + params['appid']);
      this.signinForm = this.fb.group({
        appid: oase_config.singlecompany ? oase_config.defaultyappid : params['appid'],
        user: [{ value: '', disabled: !this.appid_vorhanden }, Validators.required],
        password: [{ value: '', disabled: !this.appid_vorhanden }, Validators.required]
      });
    });
  }

  isAuth() {
    return this.authService.isAuthenticated();
  }

  getTitle() {
    return this.translation.translate('login.title') + ' - ' + this.translation.translate('project.title');
  }

  public handleError(error: Response | HttpErrorResponse | any, prefix = 'handleError') {
    let fehler = new Kernantwort();
    this._logger.log(PATH_FILE + ' - handleError error error.constructor.name: ', error.constructor.name);
    if (error instanceof Response || error instanceof HttpErrorResponse) {
      try {
        fehler = error instanceof HttpErrorResponse ? error.error : error.json();
        if (
          error.status === 0 &&
          !error.ok &&
          ((error instanceof Response && error.type === ResponseType.Error && error.statusText.length === 0) ||
            (error instanceof HttpErrorResponse && error.error.type === 'error' && error.statusText === 'Unknown Error'))
        ) {
          fehler.httpstatus = new Httpstatus();
          fehler.httpstatus.name = 'vermutlich 503er Service Temporarily Unavailable';
          fehler.httpstatus.number = 500;
        }
      } catch (e) {
        fehler = new Kernantwort();
        fehler.messagehtml = this.translation.translate('allgemein.fehler');
        this._logger.error(
          PATH_FILE + ' - ERROR ' + error.status + ': ' + prefix + ' (' + error.statusText + ' (' + error.status + ')' + '): ',
          error instanceof HttpErrorResponse ? error.message : error.text()
        );
      }
    } else {
      fehler = new Kernantwort();
      fehler.message = error.message ? error.message : error.toString();
    }

    if (!fehler.messagehtml) {
      fehler.messagehtml = fehler.message;
    }

    if (fehler && fehler.httpstatus && fehler.httpstatus.number === 500) {
      this._logger.error(PATH_FILE + ' - ' + prefix + ':' + fehler.messagehtml);
      fehler.messagehtml = this.translation.translate('allgemein.fehler');
      this._logger.error(
        PATH_FILE + ' - ERROR 500: ' + prefix + ' (' + fehler.httpstatus.name + ' (' + fehler.httpstatus.number + ')' + '): ',
        fehler
      );
    } else {
      this._logger.info(PATH_FILE + ' - ' + prefix + ': ', fehler);
    }

    // Nach dem der Fehler fertig erstellt wurde die entsprechende Fehler variable setzten
    this.fehler = fehler;

    return observableThrowError(fehler.message);
  }

  showPassword(event: any): void {
    // https://developer.mozilla.org/en-US/docs/Web/Events/mousedown
    this.password.nativeElement.type = 'text';
  }

  hidePassword(event: any): void {
    // https://developer.mozilla.org/en-US/docs/Web/Events/mouseup
    // https://developer.mozilla.org/en-US/docs/Web/Events/mouseout
    this.password.nativeElement.type = 'password';
  }
}

And the Login-Template:

<mat-card class="login">
    <mat-card-header>
        <mat-card-title>{{ 'project.title' | translate:locale.language }} - {{ 'login.title' | translate:locale.language }}</mat-card-title>
        <mat-card-subtitle>{{ 'login.subtitle' | translate:locale.language }}</mat-card-subtitle>
    </mat-card-header>
    <mat-card-content>
        <form [formGroup]="signinForm" (ngSubmit)="onSignin()" fxLayout="row wrap" fxLayout.lt-sm="column" fxLayoutGap="20px" fxLayoutGap.lt-sm="0px" fxLayoutAlign="space-between baseline" fxLayoutAlign.lt-sm="stretch stretch">
            <input matInput [hidden]="true" formControlName="appid" type="appid" id="appid" #appid required />

            <div fxFlex="0 0 100%">
                <p class="errors" *ngIf="fehler" [innerHTML]="fehler.messagehtml"></p>
            </div>

            <mat-form-field fxFlex>
                <input matInput formControlName="user" [disabled]="isSigninRunning" type="user" id="user" #user required placeholder="{{ 'login.username' | translate:locale.language }}" />
                <mat-icon matPrefix>person_outline</mat-icon>
            </mat-form-field>

            <mat-form-field fxFlex>
                <input matInput formControlName="password" [disabled]="isSigninRunning" type="password" id="password" #password required placeholder="{{ 'login.password' | translate:locale.language }}" />
                <mat-icon matPrefix>lock_outline</mat-icon>
                <span matSuffix><button type="button" [disabled]="password.value==null || password.value==''" (mousedown)="showPassword($event)" (mouseup)="hidePassword($event)" (mouseout)="hidePassword($event)" mat-icon-button class="md-24" style="height:16px; width:16px; line-height:16px;"><i class="material-icons app-input-icon">visibility</i></button></span>
            </mat-form-field>

            <div fxFlex>
                <button mat-raised-button color="primary" [disabled]="isSigninRunning || !appid_vorhanden || !signinForm.valid">
          <mat-spinner *ngIf="isSigninRunning" [diameter]="30"></mat-spinner>
          <i *ngIf="!isSigninRunning" class="material-icons app-input-icon">power_settings_new</i>
          {{ (isSigninRunning ? 'allgemein.daten.verarbeiten' : 'login.btn_login') | translate:locale.language }}
        </button>
            </div>
        </form>
        <span class="version">{{ appVersion }}</span>
        <mat-progress-bar *ngIf="isSigninRunning" color="primary" mode="indeterminate"></mat-progress-bar>
    </mat-card-content>
</mat-card>

I can't seem to find the mistake i made. I looked through this all day long and there's not even error messages coming in the debug windows.

I also tried Firefox and Chrome. With deleting the cache...

robisim74 commented 2 years ago

Hi @djanesch ,

component & template seem correct.

In the samples you provided I can't see:

export function initL10n(l10nLoader: L10nLoader): () => Promise<void> {
    return () => l10nLoader.init();
}

are you sure you are initializing the library?

Compare the doc for v12:

You could also try to add:

ngOnInit() {
        this.translation.onChange().subscribe({
            next: (locale: L10nLocale) => {
                console.log(locale);
                console.log(this.translation.data);
            }
        });
        this.translation.onError().subscribe({
            next: (error: any) => {
                if (error) console.log(error);
            }
        });
    }

and check in console if translation data are loaded without errors.

Let me know.

robisim74 commented 1 year ago

Closed due to inactivity