user7491809
user7491809

Reputation: 93

Cache issue with localization files React-i18next

I am using react and react-i18next for the localization of my app. The issue is that after updating localization files. Sometimes an old version of my json files are cached in the browser. It could be solved if the user clean the cache but I can't rely on users to know how to clear the cache. JSON files are under public\locales.

I just figured out how to disable the cache in i18next translation.json files

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: "en",
    debug: true,
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
      requestOptions: {
        cache: 'no-store',
      },
    },
    interpolation: {
      escapeValue: false, // not needed for react as it escapes by default
    },
  });

It is not an ideal solution. The better solution - translations files need to be retrieved fresh after each build. But now this does not happen, such a feeling that hash is not added to translation files How to prevent cache after a new build?

Upvotes: 7

Views: 5290

Answers (2)

Pampaka
Pampaka

Reputation: 11

You can use the version from package.json in the file request parameters. It is not a fact that translations will be changed in each release, but it is definitely better than disabling the cache or not updating it

backend: {
    loadPath: `/locales/{{lng}}/{{ns}}.json?version=${version}`
}

Upvotes: 1

Valentin Guyon
Valentin Guyon

Reputation: 1

I got the same issue using i18next-localstorage-backend which is meant to use localStorage in browser.

I simply added a defaultVersion in the init options, But in order to get a new version every build, I had to generate a random version number.

Here is my i18n.ts file:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import resourcesToBackend from 'i18next-resources-to-backend';
import Backend from "i18next-chained-backend";
import LocalStorageBackend from "i18next-localstorage-backend";

function genRandonNumber(length : number) {
  const chars = '0123456789';
  const charLength = chars.length;
  let result = '';
  for ( var i = 0; i < length; i++ ) {
     result += chars.charAt(Math.floor(Math.random() * charLength));
  }
  return result;
}

const LOCAL_DOMAINS = ["localhost", "127.0.0.1"];
const HASH = genRandonNumber(10);

i18n
  .use(Backend)
  // detect user language
  .use(LanguageDetector)
  // pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // init i18next
  .init({
    // default fallback will be french
    fallbackLng: 'fr',
    // default namespace to load
    ns: 'header',
    // load languages ressources with lazy loading and caching client side
    backend: {
      backends: [
        LocalStorageBackend, // primary ressources (cache = window.localStorage)
        resourcesToBackend((language, namespace, callback) => {
          import(`/public/locales/${language}/${namespace}.json`)
            .then((resources) => {
              callback(null, resources)
            })
            .catch((error) => {
              callback(error, null)
            })
        }) // fallback ressources (json)
      ],
      backendOptions: [{
        expirationTime: 24 * 60 * 60 * 1000 * 7, // 7 days
        defaultVersion: "v" + HASH // generate a new version every build to refresh
      }]
    },
    // debug only in dev
    debug: LOCAL_DOMAINS.includes(window.location.hostname),

    interpolation: {
      escapeValue: false, // not needed for react as it escapes by default
    },
  });

i18n.on('languageChanged', () => {
  document.documentElement.lang = i18n.language;
});

export default i18n;

My i18n instance is a bit more complicated, but in the end it will:

  1. Use localStorage to reduce networking and enable faster translation.
  2. Load only the required JSON files for a given page thanks to namespaces.
  3. Update the localStorage every new build.

If you are using multiple backends (JSON files and localStorage), you have to use i18next-chained-backend.

Upvotes: 0

Related Questions