How to make a multilingual website without redirect

Creating a language selector in JavaScript



Today, we're going to talk about how to implement a simple language selector on the basic static website, without the need of any backend or database calls or redirection to another page. We will be using only JavaScript, no PHP or other programming languages.

Serving HTML content in multiple languages is a big topic. To start with, what we’re going to do is to basically modify HTML classes by JavaScript to change the appearance of specific HTML elements on the page.
For demonstration purposes we chose the simple portfolio website.


Now we show you how to do multiple language versions on a basic website and how to switch content with JavaScript without any backend, with the added benefit of being light and fast. When we select a language in our header element, all the content we have prepared will switch to that language.

Language_selector_headerEN

Language_selector_headerES

Without further redue, let’s go into it.

Prerequisites


Surely to continue, we assume HTML, CSS and JavaScript knowledge might come handy.

Language Selectors in Header


Let's say we have a simple page with header, body etc already done, but we would like to add languages options. First we create three versions of the languages we want to have >

<div class="languageContainer">
   <div id="eng" class="languages british"><a>english</a></div>
   <div id="esp" class="languages spain"><p>español</p></div>
   <div id="svk" class="languages slovak"><p>slovensky</p></div>
</div>
<nav class="menu">
   <a href="#about" class="eng" lang="en">About</a>
   <a href="#about" class="esp" lang="es">Acerca de</a>
   <a href="#about" class="svk" lang="sk">O mne</a>
 
   <a href="#work" class="eng" lang="en">My work</a>
   <a href="#work" class="esp" lang="es">Trabajos</a>
   <a href="#work" class="svk" lang="sk">Moja praca</a>
 
   <a href="#contact" class="eng" lang="en">Contact</a>
   <a href="#contact" class="esp" lang="es">Contacto</a>
   <a href="#contact" class="svk" lang="sk">Kontakt</a>
</nav>

Now we describe what we have done. We created container <div> with a specific class to hold and visually modify its content by CSS(we show it later).


Next, we have 3 sets of languages, each have class language , again for CSS, the british, spain, slovak classes are for a set of flags we took from Country Flags - A simple API to load any country flags.

We also have a lang attribute, which will let search crawlers know that this content is in another language, they will treat that content differently, that is for a better rankings.

The most important is attribute id, this serves for the event listener - basically when JavaScript code detects we for example clicked on one of these three, it will run our code.
CSS for the upper HTML code>

.languageContainer {
  display: flex;
  justify-content: end;
  overflow: visible;
  height: 3rem;
  font-size: small;
}
.languages {
  display:flex;
  align-items: center;
  margin:.2rem;
  padding: 0.5rem;
  color: #fff;
  cursor: pointer;
}
.languages::before {
  content: '';
  display: block;
  width: 32px;
  height: 32px;
}
.british::before{
  background:url("https://www.countryflags.io/gb/flat/32.png");
}
.spain::before{
  background:url("https://www.countryflags.io/es/flat/32.png");
}
.slovak::before{
  background:url("https://www.countryflags.io/sk/flat/32.png");
}

(Note that with and height of the icons in the class languages::before correlates with the image size we have set in the URL)
(Note2 : we set nice pointer - hand will show when we move mouse cursor above the language class)

Alternatively, we can use downloaded images(icons), these are from flagpedia.net, to be sure that our page won't hang when the external source isn't available. So we made it local like this>

.british::before{
  background:url('../img/flags/unitedkingdom32x32.png')
}
.spain::before{
  background:url('../img/flags/spain32x32.png')
}
.slovak::before{
  background:url('../img/flags/slovakia32x32.png')
}

JavaScript part

Now the coding part. We would need to manipulate the appearance or disappearance of those elements with different texts. To access them, in our JavaScript file we create >

const selectedEnglish = document.getElementById("eng");
const selectedEspanol = document.getElementById("esp");
const selectedSlovensky = document.getElementById("svk");
const hidden = "display:none;";
const shown = "display:block;";

The variable hidden and shown will modify the style of the HTML element from this script.
To access all the elements with the same language, we create this code>

const allEnglishText = document.getElementsByClassName("eng");
const allEspanolText = document.getElementsByClassName("esp");
const allSlovakText = document.getElementsByClassName("svk");

Now we need to recognize what we are going to do with it. We need to switch on the one language version and by the same time switch off all the other versions.
This can be put in the function, and we need to have 3 functions for each language version. For example :
allEnglishText is a collection of all HTML elements with the same class name eng. In the function, we cycle through all such elements and we set parameter, or lets say style to all of them, and similarly, all the other language versions will not be displayed at all.

//SHOW ALL ENGLISH TEXT
function showEnglishText() {
  for (element in allEnglishText) {
     allEnglishText[element].style = shown;
  }
  for (element in allEspanolText) {
    allEspanolText[element].style = hidden;
  }
  for (element in allSlovakText) {
    allSlovakText[element].style = hidden;
  }
}
//SHOW ALL SPANISH TEXT
function showSpanishText() {
  for (element in allEnglishText) {
    allEnglishText[element].style = hidden;
  }
  for (element in allEspanolText) {
    allEspanolText[element].style = shown;
  }
  for (element in allSlovakText) {
    allSlovakText[element].style = hidden;
  }
}
//SHOW ALL SLOVAK TEXT
function showSlovakText() {
  for (element in allEnglishText) {
    allEnglishText[element].style = hidden;
  }
  for (element in allEspanolText) {
    allEspanolText[element].style = hidden;
  }
  for (element in allSlovakText) {
    allSlovakText[element].style = shown;
  }
}

Buttons and EventListeners

Until now we have created all the text in HTML and functions to show or hide them, but we also need the switch to launch the functions. We continue behind previous code by adding this>

//ENGLISH-> ALL OTHERS SWITCHED OFF
selectedEnglish.addEventListener("click", () => {
  selectedEnglish.classList.add("langSelected");
  selectedEspanol.classList.remove("langSelected");
  selectedSlovensky.classList.remove("langSelected");
 
  showEnglishText();
});

To explain, by adding event listener on the element stored in variable selectedEnglish --> that's our element in the header with id=’eng’, when we make mouse click on it, it will launch our function showEnglishText() and also we have bunch of code to add a CSS class to it, which contain border, to show off visually what button is currently clicked.
Of course we need to add all other versions>

//SPANISH-> ALL OTHERS SWITCHED OFF
selectedEspanol.addEventListener("click", () => {
  selectedEspanol.classList.add("langSelected");
  selectedEnglish.classList.remove("langSelected");
  selectedSlovensky.classList.remove("langSelected");
 
  showSpanishText();
});
 
//SLOVAK-> ALL OTHERS SWITCHED OFF
selectedSlovensky.addEventListener("click", () => {
  selectedSlovensky.classList.add("langSelected");
  selectedEspanol.classList.remove("langSelected");
  selectedEnglish.classList.remove("langSelected");
 
  showSlovakText();
});

This alone would be enough to have it working, but there is a slight problem, so far we still see all 3 versions by default, only after we click on the respective button, they hide. So we need to make sure by default there is only 1 visible by calling for example showEnglishText() function behind the definition of variables. But we can make it better as we can see in the next chapter.


Mechanism for storing the selected language in Local Storage

Now we will step up and we store the picked language into Local Storage of the user’s browser. This way user will be served the language that was last selected. That means even if the page is refreshed, it will “remember” the last selection. We create an entry to the local storage by using localStorage.setItem() in each of the event listeners, like this>

//ENGLISH-> ALL OTHERS SWITCHED OFF
selectedEnglish.addEventListener("click", () => {
  selectedEnglish.classList.add("langSelected");
  selectedEspanol.classList.remove("langSelected");
  selectedSlovensky.classList.remove("langSelected");
 
  showEnglishText();
  localStorage.setItem("languageActive", "english");
});
 
//SPANISH-> ALL OTHERS SWITCHED OFF
selectedEspanol.addEventListener("click", () => {
  selectedEspanol.classList.add("langSelected");
  selectedEnglish.classList.remove("langSelected");
  selectedSlovensky.classList.remove("langSelected");
 
  showSpanishText();
  localStorage.setItem("languageActive", "espanol");
});
 
//SLOVAK-> ALL OTHERS SWITCHED OFF
selectedSlovensky.addEventListener("click", () => {
  selectedSlovensky.classList.add("langSelected");
  selectedEspanol.classList.remove("langSelected");
  selectedEnglish.classList.remove("langSelected");
 
  showSlovakText();
  localStorage.setItem("languageActive", "slovak");
});

This way we will have stored under id languageActive the language version we just clicked on. Now its time to write the code to recover this information from Local Storage. And this is how>

//LOCAL STORAGE ADDON
switch (localStorage.getItem("languageActive")) {
 
    case "english":
      selectedEnglish.classList.add("langSelected");
      showEnglishText();
      break;
 
    case "espanol":
      selectedEspanol.classList.add("langSelected");
      showSpanishText();
      break;
 
    case "slovak":
      selectedSlovensky.classList.add("langSelected");
      //console.log("slovak on");
      showSlovakText();
      break;
 
    default:
      //default ENGLISH text shown, all others disabled
      //default -> no local storage exists
      selectedEnglish.classList.add("langSelected");
      showEnglishText();
  }

By default - if we couldnt recover anything from Local Storage, e.g. the user is the first time on your site, there will be launched code under default. We chose english to be shown first.
When there is an entry found, switch will recognize the value and it will call the respective function.

Language_selector_localStorage

Language_selector_FinalShowcase

Conclusion


We showed you how to do some very basic language switching and hopefully you liked it.

The best thing would be let the search engine know that we have localized versions of the text on our page, so they won't treat the translated text as duplicate. Because that can lead to a lot of aplicated content and that can in turn might lead in lower rank in search engines.

Surely we can make this better, for example putting all the text content (all the translations as well) into one object and selecting the desired version of the text from it with code that retrieves value from the key, but that we will do in another article. Until then!

Images by Tibor Kopca

 
by Date: 22-04-2021 Javascript web development language selector hits : 3461  
 
 
 
 

Related Posts

How to use the endsWith method in JavaScript

In this short tutorial, we are going to see what the endsWith method, introduced in JavaScript ES6, is and how it is used with strings in JavaScript. The endsWith method is…

What are javascript symbols and how can they help you?

Symbols are a new primitive value introduced by ES6. Their purpose is to provide us unique identifiers. In this article, we tell you how they work, in which way they…

Callbacks in JavaScript

Callback functions are the same old JavaScript functions. They have no special syntax, as they are simply functions that are passed as an argument to another function. The function that receives…

How to create PDF with JavaScript and jsPDF

Creating dynamic PDF files directly in the browser is possible thanks to the jsPDF JavaScript library. In the last part of this article we have prepared a practical tutorial where I…

How to make your own custom cursor for your website

When I started browsing different and original websites to learn from them, one of the first things that caught my attention was that some of them had their own cursors,…

Node.js and npm: introductory tutorial

In this tutorial we will see how to install and use both Node.js and the npm package manager. In addition, we will also create a small sample application. If you…

How to connect to MySQL with Node.js

Let's see how you can connect to a MySQL database using Node.js, the popular JavaScript runtime environment. Before we start, it is important to note that you must have Node.js installed…

JavaScript Programming Styles: Best Practices

When programming with JavaScript there are certain conventions that you should apply, especially when working in a team environment. In fact, it is common to have meetings to discuss standards…

Difference between arrow and normal functions in JavaScript

In this tutorial we are going to see how arrow functions differ from normal JavaScript functions. We will also see when you should use one and when you should use…

JavaScript Arrow functions: What they are and how to use them

In this article we are going to see what they are and how to use JavaScript Arrow Functions, a new feature introduced with the ES6 standard (ECMAScript 6). What are Arrow…

How to insert an element into an array with JavaScript

In this brief tutorial you will learn how to insert one or more elements into an array with JavaScript. For this we will use the splice function. The splice function will not…

What is the difference between primitives types and objects in JavaScript?

In this short tutorial we are going to look at the differences between primitive types and objects in JavaScript. To start with, we're going to look at what primitive types…

We use our own and third-party cookies to improve our services, compile statistical information and analyze your browsing habits. This allows us to personalize the content we offer and to show you advertisements related to your preferences. By clicking "Accept all" you agree to the storage of cookies on your device to improve website navigation, analyse traffic and assist our marketing activities. You can also select "System Cookies Only" to accept only the cookies required for the website to function, or you can select the cookies you wish to activate by clicking on "settings".

Accept All Only sistem cookies Configuration