Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not loading translations #320

Closed
othenos opened this issue Nov 22, 2020 · 2 comments
Closed

Not loading translations #320

othenos opened this issue Nov 22, 2020 · 2 comments
Labels

Comments

@othenos
Copy link

othenos commented Nov 22, 2020

This just started with Angular 10 and 11 (this particular version is 11.0.1). It runs fine in development mode but when running in production mode the translations are not getting loaded. I think the basic indicator is when subscribing to translation.onError an error is displayed "Translation Error TypeError: n.handle(...).do is not a function". Extremely difficult to debug in production mode with no ability to set breakpoints in the code. I hope I am providing enough info. If not, let me know. Thanks for your help.

import { Injectable, Inject, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

import {
    L10nConfig,
    L10nLoader,
    L10nStorage,
    L10nLocale,
    L10nTranslationLoader,
    L10nProvider,
    L10nValidation,
    L10N_LOCALE,
    L10nNumberFormatOptions,
    L10nDateTimeFormatOptions,
    parseDigits, L10nUserLanguage
} from 'angular-l10n';

export const l10nConfig: L10nConfig = {
    format: 'language-region',
    providers: [
        { name: 'app', asset: './assets/i18n/app', options: { version: '9.0.0' } }
    ],
    fallback: false,
    cache: true,
    keySeparator: '.',
    defaultLocale: { language: 'en-US', currency: 'USD' },
    schema: [
        { locale: { language: 'en-US', currency: 'USD' }, dir: 'ltr', text: 'United States' },
    ],
    defaultRouting: true
};

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

@Injectable() export class AppStorage implements L10nStorage {

    private hasStorage: boolean;

    constructor() {
        this.hasStorage = typeof Storage !== 'undefined';
    }

    public async read(): Promise<L10nLocale | null> {
        console.log('AppStorage read');
        if (this.hasStorage) {
            console.log('AppStorage has storage');
            return Promise.resolve(JSON.parse(sessionStorage.getItem('locale')));
        }
        return Promise.resolve(null);
    }

    public async write(locale: L10nLocale): Promise<void> {
        console.log('AppStorage write');
        if (this.hasStorage) {
            sessionStorage.setItem('locale', JSON.stringify(locale));
        }
    }

}

@Injectable() export class HttpTranslationLoader implements L10nTranslationLoader {

    private headers = new HttpHeaders({ 'Content-Type': 'application/json' });

    constructor(@Optional() private http: HttpClient) { }

    public get(language: string, provider: L10nProvider): Observable<{ [key: string]: any }> {
        console.log('HttpTranslationLoader');
        const url = `${provider.asset}-${language}.json`;
        const options = {
            headers: this.headers,
            params: new HttpParams().set('v', provider.options.version)
        };
        return this.http.get(url, options);
    }

}

@Injectable() export class LocaleValidation implements L10nValidation {

    constructor(@Inject(L10N_LOCALE) private locale: L10nLocale) { }

    public parseNumber(value: string, options?: L10nNumberFormatOptions, language = this.locale.language): number | null {
        if (value === '' || value == null) { return null };

        let format = { minimumIntegerDigits: 1, minimumFractionDigits: 0, maximumFractionDigits: 0 };
        if (options && options.digits) {
            format = { ...format, ...parseDigits(options.digits) };
        }

        let decimalSeparator: string;
        switch (language) {
            case 'it-IT':
                decimalSeparator = ',';
                break;
            default:
                decimalSeparator = '.';
        }

        const pattern = `^-?[\\d]{${format.minimumIntegerDigits},}(\\${decimalSeparator}[\\d]{${format.minimumFractionDigits},${format.maximumFractionDigits}})?$`;
        const regex = new RegExp(pattern);
        return regex.test(value) ? parseFloat(value.replace(decimalSeparator, '.')) : null;
    }

    public parseDate(value: string, options?: L10nDateTimeFormatOptions, language = this.locale.language): Date | null {
        return null;
    }

}
@Injectable() export class UserLanguage implements L10nUserLanguage {

    public get(): Promise<string | null> {
        let browserLanguage = null;
        if (navigator !== undefined && navigator.language) {
            // Takes the complete locale, not only the language as in the the default version
            console.log('UserLanguage ' + navigator.language);
            browserLanguage = navigator.language;
        }
        return Promise.resolve(browserLanguage);
    }
}

app.module code imports

        L10nTranslationModule.forRoot(
            l10nConfig,
            {
                storage: AppStorage,
                translationLoader: HttpTranslationLoader,
                userLanguage: UserLanguage,
            }
        ),
        L10nIntlModule,
        L10nValidationModule.forRoot({validation: LocaleValidation}),
        L10nRoutingModule.forRoot(),

app.module code providers

        {
            provide: APP_INITIALIZER,
            useFactory: initL10n,
            deps: [L10nLoader],
            multi: true
        },

app.component

    constructor(private authentication: AuthenticationService,
                private backendService: BackendService,
                private authenticationRoutingService: AuthenticationRoutingService, /* This is only here to cause the service to be loaded immediately on startup */
                private globalErrorHandlerService: GlobalErrorHandlerService,
                public router: Router,
                public route: ActivatedRoute,
                public googleAnalyticsEventsService: GoogleAnalyticsEventsService,
                public dialog: MatDialog,
                public orderService: OrderService,
                private cdRef: ChangeDetectorRef,
                @Inject(L10N_LOCALE) public locale: L10nLocale,
                @Inject(L10N_CONFIG) private l10nConfig: L10nConfig,
                private translation: L10nTranslationService) {
        this.currentUrl = '/landing';
        console.log('subscribing to router events');
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                gtag('config', 'UA-175223990-1',
                    {
                        'page_path': event.urlAfterRedirects
                    }
                );
            }
        });
        // this.translation.onChange().subscribe({
        //     next: (locale1: L10nLocale) => {
        //         console.log(locale1);
        //         console.log(this.translation.data);
        //     }
        // });
        this.translation.onError().subscribe({
            next: (error: any) => {
                if (error) { console.log('Translation Error ' + error); }
            }
        });
        console.log('generating new order');
        this.orderService.generateNewOrder();
    }

Firefox console log

AppStorage read main.1f52d5bd9627c2718941.js:1:880167
AppStorage has storage main.1f52d5bd9627c2718941.js:1:880215
HttpTranslationLoader main.1f52d5bd9627c2718941.js:1:880665
intercept - return do main.1f52d5bd9627c2718941.js:1:879395
subscribing to router events main.1f52d5bd9627c2718941.js:1:869855
Translation Error TypeError: n.handle(...).do is not a function main.1f52d5bd9627c2718941.js:1:870065
generating new order main.1f52d5bd9627c2718941.js:1:870104
GEThttp://localhost:4200/assets/images/cropped_logo.jpg
[HTTP/1.1 304 Not Modified 1ms]

Object { language: "" }
main.1f52d5bd9627c2718941.js:1:870557
Object {  }
main.1f52d5bd9627c2718941.js:1:870572
TypeError: n.handle(...).do is not a function
    intercept http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    handle http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    intercept http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    handle http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    handle http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    r http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _tryNext http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _next http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    next http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    i http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _trySubscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    call http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    call http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    call http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    r http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    l http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _innerSub http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _tryNext http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _next http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    next http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    i http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    _trySubscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    call http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    subscribe http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    loadTranslation http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    loadTranslation http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    Rb http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    Rb http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    loadTranslation http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    init http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    o http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invoke http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    onInvoke http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invoke http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    run http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    P http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    invokeTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    onInvokeTask http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invokeTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    runTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    m http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    promise callback*k http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    scheduleTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    onScheduleTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    scheduleTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    scheduleTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    scheduleMicroTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    P http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    Z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    w http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    promise callback*N/e.prototype.then/< http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    then http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    Z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    w http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    l http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    z http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    l http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    o http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invoke http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    onInvoke http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invoke http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    run http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    P http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    invokeTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    onInvokeTask http://localhost:4200/main.1f52d5bd9627c2718941.js:1
    invokeTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    runTask http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
    m http://localhost:4200/polyfills.f0fbbb0e666dfb2508c2.js:1
@robisim74
Copy link
Owner

robisim74 commented Nov 23, 2020

@Mike-Robinson The error appears to be due to an interceptor (see SO questions https://stackoverflow.com/search?q=next.handle%28%E2%80%A6%29.do+is+not+a+function), but this library does not use an interceptor or a do operator: it only fires the errors on http requests.

@othenos
Copy link
Author

othenos commented Nov 23, 2020

Thanks so much for pointing me in the right direction. And yes, it was definitely the httpInterceptor code.

@othenos othenos closed this as completed Nov 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants