Avoiding i18n caching issues in Angular

During the development of an application for a major client, we stumbled upon a scenario where the client had translation changes on a weekly (sometimes even a daily) basis with every single production release of the application. This called for a solution on how to avoid i18n translation file caching in Angular because the end users kept having the old versions of translation files cached by their browsers. Our solution might not be the best, but it is what worked out for us and the client.

 

First of all, we decided that we would have a script that would be ran before a production build that would generate a random GUID and add it to the name of translation files. The script is as follows:

 

var replace = require("replace-in-file");

 

const guid = generateGuid();

const hashRegex = new RegExp(

/(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}/g

);

const optionsHash = {

files: ["src/app/app.module.ts"],

from: hashRegex,

to: guid,

};

const path = "./src/assets/i18n";

const fs = require("fs");

 

try {

let changedFilesTimestamp = replace.sync(optionsHash);

if (changedFilesTimestamp == 0) {

throw (

"Please make sure that the file '" +

optionsHash.files +

"' has a valid GUID (UUID v4)"

);

}

fs.readdir(path, function (err, files) {

if (err) {

throw "Could not scan directory: " + err;

}

 

files.forEach(function (file) {

fs.renameSync(

path + "/" + file,

path + "/" + file.substring(0, 3) + guid + ".json"

);

console.log(

"File " +

file +

" has been renamed to " +

file.substring(0, 3) +

guid +

".json"

);

});

});

} catch (error) {

console.error("Error occurred:", error);

throw error;

}

 

function generateGuid() {

return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {

var r = (Math.random() * 16) | 0,

v = c == "x" ? r : (r & 0x3) | 0x8;

return v.toString(16);

});

}

Let us dive into on what this script does:

  1. Script requires a library which replaces text in file. We chose ‘replace-in-file’. You can install it by executing npm install replace-in-file . It also requires a file system management library and we chose ‘fs’ for this purpose. You can install it by executing npm install fs .
  2. Generate a random GUID and create a Regular Expression which describes our GUID

const guid = generateGuid();

const hashRegex = new RegExp(

/(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}/g

);

 

  1. Generate options object which replace-in-file library expects and a path to the files where we want to edit the contents of the file which match our RegEx


const optionsHash = {

files: ["src/app/app.module.ts"],

from: hashRegex,

to: guid,

};

const path = "./src/assets/i18n";

  1. Inside the try block, the synchronous replacement is executed. The return value of this operation is an array of replacement results against each file that was processed. This replaces any occurence of matching RegEx inside app.module.ts with our new GUID.

let changedFilesTimestamp = replace.sync(optionsHash);

 

  1. This is how our app.module.ts looks like after step 4.

export function HttpLoaderFactory(http: HttpClient) {

return new TranslateHttpLoader(http, "./assets/i18n/", "-c5d8b1a2-d677-41e3-9487-699a2b5e3554.json");

}

 

  1. Directory ‘path’ is then scanned for files and for every file that is found, first 4 characters of the file name are taken, then GUID is inserted and ‘.json’ extension is added.


fs.readdir(path, function (err, files) {

if (err) {

throw "Could not scan directory: " + err;

}

 

files.forEach(function (file) {

fs.renameSync(

path + "/" + file,

path + "/" + file.substring(0, 3) + guid + ".json"

);

console.log(

"File " +

file +

" has been renamed to " +

file.substring(0, 3) +

guid +

".json"

);

});

});

 

We save this script with a meaningful name in the root path of our project (we used prebuild.js as a name of choice). Now every time when we want to make a production build, we execute the following command before the build command:

npm run prebuild

 

After this, all our translation files receive a randomly generated GUID which is valid for this build version only. Our app.module.ts (place where we load our translation files) is also updated with the beforementioned GUID.

Share this post

Subscribe to our newsletter

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla.

Thanks for subscribed!

Processing...

Related posts