The Ultimate Guide to JavaScript Localization
Tags: javascript, l10n, tutorial, guide
Published: 2022-08-23 15:02:00

JavaScript is the world’s most popular programming language according to a [survey] (https://insights.stackoverflow.com/survey/2020#technology-programming-scripting-and-markup-languages-professional-developers) conducted by Stackoverflow, having a staggering 69.7% popularity score as compared to other programming languages. 

Its usefulness in both being the language of the browser and also its backend role in [Node.js](https://nodejs.org/en/) makes it the ideal developer stack.

The influence of JavaScript is also magnified by its use in many multiplatform mobile frameworks, game engines, and even in the world of cloud computing, therefore the demand for JavaScript localization comes as no surprise.

In this article, we are going to be taking a look at JavaScript localization and how to go about it in a 2-way approach. Firstly, with a file-based translation which uses Transifex to get translations and use them in our applications locally, and secondly, with the use of Transifex Native, which is a cloud-based localization stack whose SDK can be installed or used via a CDN with no need for files.


## What is Localization?

Localization involves the process of converting content to suit specific locations, i.e., multiple languages during the internationalization of your project. It simply means to design software in a way that can handle multiple locations, languages, and regions. 

Localization also doesn’t just dwell on languages, it can also be used to address some other forms of media which include images, voice notes, and embedded sounds locals would be very familiar with in their specific regions.

There are a lot of possibilities out there on how to achieve localization with JavaScript but most developers are uncertain on how to go about it, whether it's selecting the right tools, frameworks, or libraries; there’s a whole lot of research and brainstorming that needs to be done to make the process smoother.

This step-by-step guide aims to teach you all that you need to know to localize a JavaScript website, app, or software with Transifex, a platform that’s ideal for the task of localization and internationalization for any level of developer. 

## Ways to Localize a JavaScript Project

There are two ways to localize your javaScript project which are:

1. File-based: Meaning that your content needs to be extracted in the form of a file and uploaded to the Translation Management System (TMS), then you would typically translate the content, download it back from the TMS and upload it back to your app/website and deploy the changes.

2. Fileless: This process involves installing a plugin directly to your code and having the TMS sync your translations without having to go through the above-mentioned process


## The File-Based Approach to JavaScript Localization

Internationalization as earlier defined is the process of designing and building software so it can be adaptable to different users from different cultures, regions, and languages. It also entails adapting software to accept several forms of data and settings to match local customs to be processed correctly.

In the process of designing software to suit several languages as described above, your approach might be to have code locally localized without the use of libraries, a CDN, or several configuration exercises. This local process is highly feasible as it involves creating local files which have been translated by several individuals into different languages.

Alright, let’s say we have a page we want to localize as shown below:

```HTML
<!-- ./index.HTML -->

<html lang="en">
    <head>
        <title>JavaScript Transifex Demo</title>
    </head>
    <body>
        <div class="container">
            <nav class="navbar">
                <div class="container">
                    <div class="logo">
                        <h1>Local JS</h1>
                    </div>
                    <div class="navbar-right">
                        <select id="localization-switcher" class="locale-switcher">
                            <option value="en">English</option>
                            <option value="fr">French</option>
                            <option value="ar">Arabic (العربية)</option>
                        </select>
                    </div>
                </div>
            </nav>
            <div class="content-section">
                <h1 localization-key="title">
                    Welcome to this localization demo site
                </h1>
                <p localization-key="description">
                    Software localization is the process of adapting software to the culture and language of an end user, from standards of measurement to video and graphic design. It involves translation, design, and UX changes to make software look and feel natural to the target user.
                </p>
            </div>
        </div>
        <script src="./js/script.js"></script>
    </body>
</html>
```


The current content in the code is hardcoded, and for the purpose of file-based localization, all the content is extracted into a file, most likely in a JSON format, and then retrieved from a file.
The next step is to make a file in a language folder within your code to keep track of all files for different languages:

```JSON

<!-- ./lang/en.json -->

{

    "title": "Welcome to this localization demo site",

    "description": "Software localization is the process of adapting software to the culture and language of an end user, from standards of measurement to video and graphic design. It involves not only translation but also design and UX changes to make software look and feel natural to the target user."

}

```
A fetch request can then be used to replace the static content in the HTML file with the content from the JSON below:

```js

<!-- ./js/script.js -->

let translations = {};

const fetchContent = () => {

    return fetch(`lang/en.json`)

        .then((response) => {

            return response.json();

        })

        .then((data) => {

            translations = data;

            translatePage();

        });

};

fetchContent();

const translatePage = () => {

    document.querySelectorAll('[localization-key]').forEach((element) => {

        let key = element.getAttribute('localization-key');

        let translation = translations[key];

        element.innerText = translation;

    });

};

```
We’ve successfully retrieved the entire content from the JSON file in the above code snippet. Here the querySelectorAll() method was used to find all elements with the “localization-key” property that we assigned in our HTML file, looped through to see the attribute that matched the key of our object, and finally embedded the data.

So far so good, we’ve seen how to read data from a file using vanilla JavaScript, however, for file-based localization, Transifex allows the upload of a source file which is the English version of our content for this demo (`en.json`). After this initial stage, a platform can then be used to translate the content, after which it can be downloaded and the localized content fetched.

We’ll look at how to create a file-based project on Transifex and then upload our source content for translation. Transifex would take care of the translation and we can then download the translated content.

## How to Create a File-Based Project on Transifex

The first point of entry into the Transifex universe is by creating an account. You can Sign Up with your GitHub, Google, or LinkedIn account, which is free for 15 days, and free forever for open-source projects.

After account creation, you need to create a project. A name must be given to the project and “File-based” should be selected as your project type.

![JavaScript Localization - File-based - Transifex](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tqwatscxsd59zz30ii1.png)

Finally, you must specify your application’s primary language and the language(s) into which we will translate it. We’ll use English as the primary language for this guide, with French and Arabic as our target languages.

**Note**: Uncheck the box that asks if you want to add a demo file automatically unless you want to use it to test the Transifex platform first.

When you finish, click on the “Create Project” button.
Following that, we will direct you to the next page, where you can upload your source file in any supported format. but we will use the JSON format.

After creating your project, select the “Upload file” button to upload your extracted JSON file:

![JavaScript Localization - File-based](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66o02jr1x0dhlibjx8q3.png)

When that is done, you’re all set to start translating your content into the editor!

## Downloading Your Translated Content From Transifex

After the above process has been finalized, we can go ahead with downloading the translated file after successful translation into the content of our application. 

To download the translated file, navigate to your project’s language tab, click on the file, and then select “**Download only reviewed translations**”. Transifex will allow us to download a JSON file of your translated language:

![JavaScript localization guide](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5ir8n87g8uyp65c9kqm.gif)

**Note**: Please ensure to save the file with the locale name in the `lang` folder we created earlier, e.g., `./lang/ar.json`.

## Loading Translations Asynchronously From Local Files

We’re off to a good start by translating our source file (`en.json`) into Arabic (`ar.json`), and we have saved both in the languages (`lang`) folder. We were also able to load data from the source file previously. Now, let’s implement loading our translations asynchronously: 


```js

const locale = 'ar';

let translations = {};

document.addEventListener('DOMContentLoaded', () => {

    setLocale(locale);

});

const setLocale = async (newLocale) => {

    translations = await fetchTranslations(newLocale);

    translatePage();

};

const fetchTranslations = async (newLocale) => {

    const response = await fetch(`lang/${newLocale}.json`);

    return await response.json();

};

const translatePage = () => {

    document.querySelectorAll('[localization-key]').forEach((element) => {

        let key = element.getAttribute('localization-key');

        let translation = translations[key];

        element.innerText = translation;

    });

};

```
The code above is very similar to the code we used to retrieve data from the source file. We’re doing it asynchronously, so it loads content based on the `**locale**` parameter. Let’s go over the code again.

First, we declared two variables to specify the locale we want to retrieve based on the available locales. As we can see, we set ours to `**ar**`, which is the language code for Arabic:

```js
const locale = 'ar';
let translations = {};
```

We then created an `**addEventListener()**` that gets triggered when the page content is readily using the `**DOMContentLoaded**` event. In this `**addEventListener()**` we called the `**setLocale()**` function and passed the `**locale**` variable.

```js
document.addEventListener('DOMContentLoaded', () => {
    setLocale(locale);
});
```

The core function is `setLocale()`, and it performs two major tasks: 

1. Loading translations for the given locale 

2. Translating the page to show specified language localized content:

```js
const setLocale = async (newLocale) => {
    translations = await fetchTranslations(newLocale);
    translatePage();
};
```
As seen in the `**setLocale()**` function, we first fetched our translations, and as we can see, we used async/await to get the translations before triggering the function that will load our page with the fetched content. We passed the locale to the `**fetchTranslations()**` function and used it to retrieve content from the locale file:
```js
const fetchTranslations = async (newLocale) => {
    const response = await fetch(`lang/${newLocale}.json`);
    return await response.json();
};
```
Finally, when we have gotten the content, we now pass this content to our page, so it appears using the second function in the setLocale function, which is `**translatePage()**`:

```js
const translatePage = () => {
    document.querySelectorAll('[localization-key]').forEach((element) => {
        let key = element.getAttribute('localization-key');
        let translation = translations[key];
        element.innerText = translation;
    });
};
```

## The Fileless-Based Approach to JavaScript Localization

The fileless-based approach to [JavaScript Localization](https://www.transifex.com/blog/2022/javascript-localization/) is what we can describe as “**Transifex Native**”. 

This approach enables you to allow the localization platform directly communicate with your codebase and allow pull/push content automatically. This approach is a better alternative to the traditional approach involved in the file-based approach to localization. Here’s how to get started with a fileless-based approach:

1. Create a Transifex account if you don’t have one already.

2. Create a Transifex Native project.

3. Specify your application’s primary language and the language(s) into which we’ll translate it.

For this guide, English would be the primary language while French and Arabic are going to be the target languages. When finished with all of the above, click on the Create Project button, after which you will be directed to the next page where you’ll find instructions for creating credentials for your project.

At the bottom of the page, click on “**Generate Native Credentials Now**”. The **API _token_** and **_secret_key** would be displayed in a pop-up window. Go ahead and copy both keys and safeguard them because they’re going to be very useful later. Clicking on the button would also show us the configurations we’ll use in our JavaScript file.

![JavaScript Localization - Fileless - Transifex Native](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5w34lwqy8vug9dch98j.png)

Once all that is sorted, we can now proceed to push the content to Transifex and then localize it.

## How to Configure Transifex Native in Our JavaScript Project

The first step into using Transifex native is configuring it. This can be done in numerous ways as seen in the [Transifex JavaScript Documentation](https://developers.transifex.com/docs/javascript-sdk-setup). However, for this particular guide, we’ll make use of the CDN and later make use of the Transifex CLI when we want to push our content.

Now, let’s add the CDN to our HTML file and then we’ll be able to use Transifex directly in our JavaScript file.

```HTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>JavaScript Transifex Demo</title>
    </head>
    <body>
   // ...
       <script
            type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@transifex/native/dist/browser.native.min.js"
        ></script>
        <script src="./index.js"></script>
    </body>
</html>
```

Once this is done, we can then head over to our JavaScript file to configure Transifex using the token we got earlier when creating our project.

```js
const tx = Transifex.tx;
const t = Transifex.t;
tx.init({
    token: 'ADD TOKEN KEY HERE.'
});
```

## How to Push Content to Transifex with JavaScript

We’ve successfully configured Transifex locally in our JavaScript file after following the above steps. Now, we want to push our content directly with the Transifex CLI without the use of any external files as seen in the file-based approach.

To achieve this, we have to first create a package.json file and then install the Transifex CLI dependency by running the following commands:

```bash

$ npm init -y

$ npm install @transifex/cli --save

```

Once this is done we will see that Transifex CLI has been installed in our package.json file dependency object:

```JSON
"dependencies": {
    "@transifex/cli": "^4.2.2"
}
```

We can now proceed to push our content with the `t` function. As we can see below, we also used the `_key` parameter to give each content a key, so it’s easy to fetch that content later:

```js
const tx = Transifex.tx;
const t = Transifex.t;
    tx.init({
        token: 'ADD TOKEN KEY HERE',
    });
    t('Welcome to this localization demo site', {
        _key: 'title',
    });
    t(
        'Software localization is the process of adapting software to both the culture and language of an end user, from standards of measurement to video and graphic design. It involves not only translation, but also design and UX changes to make software look and feel natural to the target user.',
        {
            _key: 'description',
        }
    );
```
So far, we have initialized the content we want to push to Transifex for localization. Let’s now push the content with the `@transifex/cli` library, which will collect all translatable strings and push them to Transifex using the following command:

```
$ ./node_modules/.bin/txjs-cli push src/ --token=<PROJECT TOKEN> --secret=<PROJECT SECRET>
```

**Note**: In the command above, ensure you add your token and secret key. You will also notice that we use `src/`, which means this command will look for the `index.js` file in the `src` folder.

The `index.js` file is the file that contains the content we want to push. Ensure you place your HTML, CSS, and JavaScript file in an `src` folder as seen in this [GitHub repository](https://github.com/olawanlejoel/JS-localization-transifex/tree/main/Transifex%20Native).

## How to Pull Localized Content From Transifex

Retrieving content from Transifex is similar to how we first retrieved data from JSON files. Here, the only significant difference is that there is no need for the use of the fetch API for data retrieval.

```js
const locale = 'ar';
document.addEventListener('DOMContentLoaded', () => {
    setLocale(locale);
});
const setLocale = (newLocale) => {
    tx.setCurrentLocale(newLocale)
        .then(() => {
            translatePage();
        })
        .catch((err) => console.log(err));
};
const translatePage = () => {
    document.querySelectorAll('[localization-key]').forEach((element) => {
        let key = element.getAttribute('localization-key');
        let translation = t(key);
        element.innerText = translation;
    });
};
```

In the code above, we specified the locale from which we wanted to retrieve its localized content. We created a function to retrieve the data, which is the `**setLocale()**` method, and finally, we used the `**translatePage()**` method to help get each content based on the `key` and pass it to the UI.

## Conclusion

In this step by step guide, we learned the two major methods for implementing JavaScript localization, namely, File-based and Fileless.

Both methods work effectively. But for large projects, the file-based approach becomes extremely difficult to manage.

This scalability deficit brings to light the efficiency of Transifex native in localization as translations are not included in your codebase as shown in this guide. 

Need more info on how fileless JavaScript localization works? Feel free to check out [Transifex Native's documentation](https://docs.transifex.com/javascript-sdk/).