aurelia / i18n

A plugin that provides i18n support.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Defaulttranslations gets cached when xhr requests fails

groenlid opened this issue · comments

I'm submitting a bug report

  • Library Version:
    "aurelia-i18n": "2.0.0",

Please tell us about your environment:

  • Operating System:
    Linux Solus Mate

  • Browser:
    all

  • Language:
    Typescript 2.8.3

Current behavior:

export const configureLanguage = (aurelia: Aurelia) => {
    aurelia.use.plugin(PLATFORM.moduleName('aurelia-i18n'), (instance: I18N) => {
        instance.i18next
            .use(XhrBackend)
            .use(LngDetector)
            .use(Cache);

        return instance.setup({
            backend: {
                loadPath: endpoints.translation
            },
            cache: {
                enabled: ENV === 'production',
                expirationTime: 4 * 60 * 60 * 1000,
            },
            attributes: ['t', 'i18n'],
            debug: true,
            crossDomain: true,
            fallbackLng: 'en',
            joinArrays: ', ',
            load: 'languageOnly',
            detection: {
                order: ['localStorage', 'navigator', 'htmlTag'],
                lookupLocalStorage: 'i18nextLng',
                htmlTag: document.documentElement
            }
        })
        .then(() => aurelia.container.get(AppRouter).transformTitle = (title: string) => instance.tr(title));
    });
};

In the case where the xhr request to our translation-service fails, the cache is still populated with the default-translations included in aurelia-i18n. The next times the user refreshes the page, the cache with the wrong values is returned until it expires.

  • What is the expected behavior?
    Nothing should be cached and the request should run again the next time the page loads.

  • Suggestion
    Have the ability to not include the defaultTranslations for relative-time. Both for smaller bundles and so that nothing is cached when the request fails.

I'm not sure I fully understand the problem. Caching is part of i18next and is nothing that is specifically touched by the aurelia-i18n plugin. But besides that it sounds like the key problem is the automatic registration of defaultTranslations, namely for the relative-time feature right? What is wrong with the translations? Or do you simply prefer loading custom ones?

Nevertheless the reason, with regards to the defaultTranslations, we could add another plugin configuration option, which when set, won't load any defaultTranslations. That means of course you'd have to provide them all by yourself for the languages of choice. Would that be helpful to solve your issue?

Yes. The problem for us is the automatic registration. We do not use them, and by including them, I don't see how we could stop the i18next-localStorage-cache from caching when the xhr-request fails and it's only given the default-values included in aurelia-i18n.

Adding a configuration-option would fix our problem 👍

Do you want to go ahead and try creating a PR for that? If you need any guidance just ping me either here or on gitter

This issue seems to have been resolved by upgrading aurelia-i18n to the latest version + using i18next-chained-backend instead of using xhrbackend and localstorage-backend separately.

Thanks for the support! 👍

Ahh cheap trick to avoid a PR :)

May I just ask you to post how your new instance setup looks like with your adaption?
https://github.com/i18next/i18next-chained-backend indeed looks nice

sure :)

Here's our current setup, but I'm looking into having the caching part in our serviceworker instead of localstorage :)

const fetchNewLanguageTexts = (i18next: any, logger: Logger) => {
    const getCacheName = (language: string) => cachePrefix + language + '-translation';
    const languages: string[] = i18next.languages;

    const toReload = languages.filter(language => {
        const storedValue = window.localStorage.getItem(getCacheName(language));
        if (storedValue === undefined || storedValue === null) return false;
        const parsed = JSON.parse(storedValue);
        const timeFetched = parsed.i18nStamp;

        const shouldReload = timeFetched < new Date().getTime() - TIME.MINUTEINMS * 30;

        i18next.on('failedLoading', (lng: string, ns: string, msg: string) => {
            logger.error('Failed reloading languagetext. Will fall back to cached texts', lng, ns, msg);
            if (lng === language)
                window.localStorage.setItem(getCacheName(language), storedValue);
        });

        return shouldReload;
    });

    if (!isEmpty(toReload)) {
        toReload.map(getCacheName).forEach(cache => window.localStorage.removeItem(cache));
        i18next.reloadResources(toReload);
    }
};

/**
 * Translations initial visit
 * - Fetch language-texts from server
 * - Render
 * - Cache language-texts
 * Translations second visit
 * - Fetch translations from cache
 * - Render
 * - Fetch language-texts from server
 * - Rerender
 * - Cache language-texts
 */
export const configureLanguage = (aurelia: Aurelia) => {
    aurelia.use.plugin(PLATFORM.moduleName('aurelia-i18n'), (instance: I18N) => {
        instance.i18next
            .use(Backend)
            .use(LngDetector);

        const CacheOptions = {
            enabled: ENV === 'production',
            expirationTime: TIME.DAYINMS * 365,
            prefix: cachePrefix
        };

        const XhrOptions = {
            loadPath: endpoints.translation
        };

        return instance.setup({
            backend: {
                backends: [ Cache, XhrBackend ],
                backendOptions: [CacheOptions, XhrOptions]
            },
            attributes: ['t', 'i18n'],
            debug: true,
            crossDomain: true,
            fallbackLng: 'en',
            joinArrays: ', ',
            load: 'languageOnly',
            detection: {
                order: ['localStorage', 'navigator', 'htmlTag'],
                lookupLocalStorage: 'i18nextLng',
                htmlTag: document.documentElement
            }
        }).then(() => {
            aurelia.container.get(AppRouter).transformTitle = (title: string) => instance.tr(title);
            if (isLocalStorageAvailable)
                fetchNewLanguageTexts(instance.i18next, getLogger("Languagetests"));
        });
    });
};