Deliver translated files seamlessly via Localazy CDN

As developers, we want to deliver content fast, secure, and reliably to our users. In the case of a small business website, it's no issue leaving all of the content stored with the website's hosting provider. But when your project becomes bigger and bigger, you must be able to scale accordingly. In regards to the scalability of localization files delivery, we got your back with the Localazy CDN.

πŸ€” What is a CDN?

CDN is an abbreviation for Content Delivery Network. At its core, it's a network of servers also named Points of Presence (PoPs) that store replicas of content in their memory (cache) and then deliver it to requesting users. The geographic location determines this delivery to connect the user to the nearest and fastest server, reducing data transfer time (latency)..

What is a language CDN?

At Localazy, we strive to help developers worldwide with localization. Localazy language CDN delivers the up-to-date translations reliably and directly to the distributed version of your project, without the need of having to download and update the translation files every single time you make an update.

All of this is powered by the reliable AWS CloudFront.

Learn more about Localazy CDN in the documentation.

Localazy CDN vs. OTA updates

We designed the Localazy CDN to work mainly with web applications. For mobile apps (Android & iOS), we have OTA (Over-the-air) updates. Both serve the same purpose, which is delivering translated content directly to your users.

The difference is that our OTA Updates already come with a library/SDK for Android & iOS. The library/SDK will then automate the process of distributing the content for you. There are so many available options to implement the CDN that we leave it to our users to decide their best approach.

Learn more about OTA Updates in the documentation.

Is Localazy CDN free or paid?

Localazy CDN is available with the Free plan, and is a part of Online Services so the pricing is usage based.

You can check the pricing here.

πŸ•ΉοΈ Sample project

To illustrate the use of CDN, we'll put together a simple project in JavaScript using the i18next library.

We will build this example project with the help of the article: JavaScript app localization with i18next and Localazy.

Creating the project

Let’s start with an empty project. Β We'll be using npm to manage dependencies, so we'll need Node.js installed. You can verify the installation by running npm -v.

mkdir cdn-js-app && cd cdn-js-app && npm init

After running the above command and answering the initial questions, a package.json file should be created. We'll use the following structure to hold our project:

.
β”œβ”€β”€ index.html
β”œβ”€β”€ package.json
β”œβ”€β”€ src
β”‚   β”œβ”€β”€ i18n.js
β”‚   └── index.js
└── style.css

Inside the index.html file, paste the following code. We will not modify it anymore, meaning that all content will be created dynamically with JavaScript.

<!DOCTYPE html>
<html>
<head>
  <title>Localize Javascript App with Localazy's CDN</title>
  <link rel="stylesheet" href="style.css"/>
  <meta charset="UTF-8" />
</head>
<body>
  <div id="app"></div>
  <script src="src/index.js">
  </script>
</body>
</html>

To make it easier to work with the project, we'll install the parcel-bundler first. If you don't know Parcel yet, it's a web application bundler with a great developer experience.

Parcel offers blazing-fast performance and requires zero configuration. So basically, with one package installed, you'll get a development server with hot-reloading and production builds. Excellent for quick projects and rapid prototyping.

npm install -D parcel-bundler

You can then simplify running the Parcel bundler by adding a run and build task to the scripts section in your package.json.

{
  "scripts": {
    "start": "parcel index.html --open",
    "build": "parcel build index.html"
  }
}

Add source language to Localazy

Because we will get our language file with externalized strings through the CDN, we should first add it to Localazy.

To do that, we will start by creating a translation file, and we'll name it en.json. Inside it, we'll place the following English strings, as it is our source language:

{
  "hello_localazy": "Hello Localazy!",
  "cdn_testing": "We're testing the CDN",
  "using_javascript": "In this project we decided to use JavaScript",
  "cdn_info": "With the CDN you can deliver the translation files instantly"
}

To add the file to Localazy, sign up or log in and when you find yourself in the dashboard, click Add New App.

Creating a new app in Localazy

Here, you can name your app, set it public or private, and decide whether to use community translations (ShareTM) for your project.

Now that our app is created, we can add the language file through the File management screen.

Localazy File management screen

Click the βž• blue button in the top right, drag and drop the file, pick your choices and upload it.

Localazy File management screen

Our file is officially uploaded and ready to be implemented with the CDN.

🌎 Integrating the project with Localazy CDN

As a next step, we’re going to install the i18next library. It will help us to quickly load all the locales we have.

npm install i18next

The following code needs to be added to our i18n.js file:

// i18n.js
import i18next from "i18next";
export const i18n = i18next;
export const fetchLanguage = async (code) => {
  const result = await fetch(`https://delivery.localazy.com/_a855374211039568660198b39c31/_e0/dfe5b84c1598c8c56b6f1a11efcd483bb3f417ea/${code}/file.json`);  
  return result.json();
}
export const initI18n = async (callback) => {
  const result = await fetchLanguage("en");
  i18next.init({
    lng: "en",
    debug: true,    
    resources: {
      en: {
        translation: result
      },
    },
  }, function (err, t) {
    // Call this function once i18next is initialized
    callback()
  });
}

It works by creating the fetchLanguage function that loads the specific JSON file from the CDN. The input parameter is the language code; notice that the fetch function inside contains the file URL. This URL can be obtained by clicking on the three dots of the file we uploaded in the File Manager or clicking the button right next to it.

Localazy CDN option in the File management

The URL in the function has been modified with a ${code} placeholder, and this placeholder is going to be used to fetch the different language files dynamically.

Looking at the index.js file, we will need to use the following code to show the strings on the screen.

// index.js
import { i18n, initI18n } from "./i18n";
const initPageContent = () => document.write(`
${i18n.t("hello_localazy")}
<br><br>
${i18n.t("cdn_testing")}
<br><br>
${i18n.t("using_javascript")}
<br><br>
${i18n.t("cdn_info")}
`);
initI18n(initPageContent);

Depending on your browser, you might have to add the code below to the package.json file or you can get an Uncaught ReferenceError: regeneratorRuntime error.

"browserslist": [
    "last 1 Chrome version"
  ]

Once done, try to run the development server with npm start.

The desired output

You should see the above result if you set everything up correctly.

Implementing a language switcher

What we implemented above is a basic setup of the CDN, and it's enough for one language, but if you're reading this, most likely you want your project translated into different languages.

For this, we will dynamically fetch all the languages you have associated with your project at Localazy, and we will display them with a simple language switcher, all of this without the need for any local files.

Fetching different language files

Our fetchLanguage function in our i18n.js file accepts language codes to fetch the string files, but we would have to add them manually each time we add a new language. Luckily for us, Localazy offers you a CDN metadata file. This file contains objects with data for each locale we have on our project.

First things first: we should add more languages to our project. To do this, we head back to our project at Localazy and click on the Translations tab. Here, we can see the Add Languages tab, where we can choose the languages we will add to our project.

Adding Languages in Localazy

We will choose European Portuguese (pt_PT) and Spanish (es) for this example, but feel free to choose whatever languages you would like to add.

Your screen will then look like this:

Added Languages in Localazy

To start translating them, click the blue button on your selected language, and you'll be redirected to this screen:

Translating the strings

When all the languages have been translated, this is what it'll look like:

Translated languages in Localazy

We now need to fetch all the string files. To do that, we will use the metadata file to get the language codes associated with the languages we translated. After we get the language codes, we will then fetch the language file using the fetchLanguage function.

We will need the metadata URL, which can be accessed from Localazy CDN options:

Localazy CDN option in the File management

To fetch the metadata file, we will add the following functions to the i18n.js file:

export const fetchLocalazyMeta = async () => {
  const result = await fetch(`https://delivery.localazy.com/_a855374211039568660198b39c31/_e0.json`); 
  localazyLocales = Object.values(await result.json())[0]["locales"];
}

In this function, the metadata file is already being processed for the locales objects to be added into an array called localazyLocales, making it easier to access.

To extract the language codes, we use this function:

export const getSupportedLangCodes = () => {
const languages = localazyLocales.map(
    (locale) => {
      let langCode = locale.language;
      if (locale.region) {
        langCode = langCode + "-" + locale.region;
      }
      return langCode;
    }
  );
  return languages;
}

This function retrieves the language parameter from the metadata file, and if it has a region associated with it, it will add it to the string, creating the language codes.

To get the current language, we use the following code:

export const getCurrentLanguage = () => {
  return window.localStorage.i18nextLng || 'en';
}

To get all languages, we have this:

export const getLanguages = ()=>{
  return localazyLocales;
}

This last two functions are needed in the index.js file.

export const initI18n = async (callback) => {
  await fetchLocalazyMeta()
  const langCodes = getSupportedLangCodes();
  const result = await Promise.all([
    ...langCodes.map(lng=> fetchLanguage(lng))
  ]);
  let resources = {};
  result.forEach((res,index)=>{
    resources[langCodes[index]] = {translation: res};
  })
  i18next.init({
    lng: "en",
    fallbackLng: "en",
    debug: true,
    supportedLngs: langCodes,
    resources,
  }, function (err, t) {
    callback()
  });
}

This the last function of our i18n.js file, it will separate the locales and allow them to be displayed in index.js.

The full content of the i18n.js file is:


import i18next from "i18next";
export const i18n = i18next;
export let localazyLocales = [];
export const fetchLanguage = async (code) => {
  const result = await fetch(`https://delivery.localazy.com/_a855374211039568660198b39c31/_e0/dfe5b84c1598c8c56b6f1a11efcd483bb3f417ea/${code}/file.json`);  
  return result.json();
}
export const fetchLocalazyMeta = async () => {
  const result = await fetch(`https://delivery.localazy.com/_a855374211039568660198b39c31/_e0.json`); 
  localazyLocales = Object.values(await result.json())[0]["locales"];
}
export const getSupportedLangCodes = () => {
const languages =localazyLocales.map(
    (locale) => {
      let langCode = locale.language;
      if (locale.region) {
        langCode = langCode + "-" + locale.region;
      }
      return langCode;
    }
  );
  return languages;
}
export const getCurrentLanguage = () => {
  return window.localStorage.i18nextLng || 'en';
}
export const getLanguages = ()=>{
  return localazyLocales;
}
export const initI18n = async (callback) => {
  await fetchLocalazyMeta()
  const langCodes = getSupportedLangCodes();
  const result = await Promise.all([
    ...langCodes.map(lng=> fetchLanguage(lng))
  ]);
  let resources = {};
  result.forEach((res,index)=>{
    resources[langCodes[index]] = {translation: res};
  })
  i18next.init({
    lng: "en",
    fallbackLng: "en",
    debug: true,
    supportedLngs: langCodes,
    resources,
  }, function (err, t) {
    callback()
  });
}
Creating the language switcher element

Now that we can dynamically load the files, we must present them in the browser. We will use this very simple language switcher in index.js to easily switch between languages.

import { i18n, initI18n, getLanguages, getCurrentLanguage, getSupportedLangCodes } from "./i18n";
const createLanguageSelector = () => {
    const languages = getLanguages();
    const langCodes = getSupportedLangCodes();
    let template = '<select id="selector">';
    languages.forEach((l, i) => {
        template += `
    <option ${l.language === getCurrentLanguage() ? "selected" : ""} value="${langCodes[i]}">
      ${l.localizedName}
    </option>`
    })
    template += '</select>';
    return template;
}
const getTranslatedContent = () => {
    return `${i18n.t("hello_localazy")}<br><br>
  ${i18n.t("cdn_testing")}<br><br>
  ${i18n.t("using_javascript")}<br><br>
  ${i18n.t("cdn_info")}<br><br>`;
}
const updateTranslatedContent = () => {
    document.querySelector("#content").innerHTML = getTranslatedContent();
}
const initPageContent = () => {
    document.querySelector("#app").innerHTML = `  
  ${createLanguageSelector()}   
  <div id="content">  
    ${getTranslatedContent()}
  </div>`;
    document.querySelector("#selector").addEventListener("change", (e) => {
        i18n.changeLanguage(e.target.value);
        updateTranslatedContent();
    })
}
initI18n(initPageContent);

After running the development server with Β npm start , we should now see this outcome:

The language switcher

Adding a new language

The best part is that everything is automated now. If we decide to add a new language in the project in Localazy, we will have it automatically added to the project without any intervention βš™οΈ.

German language added
Please remember that the CDN works with cached memory. It might take a bit to refresh the content after it's been added. Just sit back, relax, and soon it'll be delivered ⛱️.

βœ”οΈ Closing words

We hope you enjoyed this tutorial and learned how to set up the CDN and how easy it is to start localizing any JavaScript app with it. This might just be the advantage you need for your projects to stay aheadπŸ₯‡.

There are obviously various ways you can take to achieve the output above. Feel free to use the code or modify it to your needs.

If you would like to play around with the prototype, you can check it out on CodeSandbox. The whole git repository is available on GitHub. If you have any questions, join us on our Localazy Discord for a chat.


This is a companion discussion topic for the original entry at https://localazy.com/blog/deliver-translated-files-localazy-cdn-tutorial