Problem Solving
Overengineering a simple feature in javascript. Translations made easy

Overengineering a simple feature in javascript. Translations made easy

In the current state of the web, it is very rare to see static websites. The reason could be very obvious, most sites would like to offer some kind of personalized experience or sell goods (physical or digital) which can’t be done with a static site.

However static sites still have some uses, especially on personal websites, some kind of portfolio or gallery, anything that doesn’t need to be updated with much frequency. Following that line of thought my personal website is actually static. It is very boring and cringey, but hey! it loads crazy fast.

The original script

Anyway, the only functionality I added to the site besides the content was the possibility to change language between English and Spanish, just depending on Jquery and a simple script that will use some json files as source for the text.

var language; 
function getLanguage() {
  (localStorage.getItem('language') == null) ? setLanguage('en') : false;
  var url = 'language/' +  localStorage.getItem('language') + '.json';
  $.ajax({ 
    url:  'language/' +  localStorage.getItem('language') + '.json', 
    dataType: 'json', async: false, dataType: 'json', 
    success: function (lang) { language = lang } 
  });
}

function replaceStrings(){
  getLanguage();
  $('.to_translate').each(function (i){
    var sel=  `${this.id}`;
    if (sel != ''){
      $(`#${sel}`).html(language[this.id]);
    }
  });
}

function setLanguage(lang) {
  localStorage.setItem('language', lang);
  replaceStrings();
}

$(document).ready(function(){
  replaceStrings();
});
Code language: JavaScript (javascript)

This was simple enough but there were a couple of things that I didn’t like about it. The first one was that it completely replaces the content of the element without escaping the html, that meant I could write html in my json files to get some rich text. It worked fine but the implementation seemed a bit dirty to me.

The second thing I didn’t like was to depend on jquery, since this was made in a rush it was ok, but for something like this, there should be a solution that didn’t require to depend on another library. That’s how I decided, 2 years later, to rebuilt the thing, and make it into a tiny reusable library (or a really big javascript snippet depending on the perspective).

The rewrite, meet Spat

I wrote the original script two years ago, so I was able to look into it with fresh eyes, and besides the couple of things I mentioned before I didn’t like, I wanted this script to be easy to add and use ideally with very little if not any code added to the html. I was using an additional class to mark all the elements that needed to be translated “.to_translate”, this needed to go.

First thing we needed to resolve was to cut our dependency on jquery, and the tricky part about it was to find a replacement for this callback:

$(document).ready(function(){
  replaceStrings();
});
Code language: JavaScript (javascript)

There was already a solution in place for it in vanilla Javascript, but it wasn’t as reliable as the jquery version, so I did a few adjustments to make it work more or less as its jquery counterpart:

function ready(callback){
    if (document.readyState != 'loading') callback();
    else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
    else document.attachEvent('onreadystatechange', function(){
        if (document.readyState=='complete') callback();
    });
}
Code language: JavaScript (javascript)

Next, since I didn’t like the total replacement of the inner HTML of an element, I tried a solution where only the Text will be replaced and any other node inside the element will be kept. I achieved this just checking the nodes inside an element until I found a TEXT_NODE

if (node.nodeType === 3)
Code language: JavaScript (javascript)

And that was it, at least for the moment. So I started documenting the usage… This is where I realized how hard it can be to put into words a comprehensive guide on how to use your code, It took me around 2 hours to have something I liked, basically the same time it took me to code and test the damn thing. A final commit and push and Spat is ready to use.

It’s not enough

Once that was done I tried to replace the code in my site with this new “library” but then I realized that I actually needed some rich text for some of my paragraphs, There were some bold text and even a link. Obviously I could have adjusted the HTML in my page to work with the library, but the idea from the beginning was to use the library with minimum changes (ideally none) in the HTML. So I needed a way to add rich text, and that meant to contradict an statement I did earlier in this post.

it should only replace text.

The solution to this involved returning to replace the entire content of an HTML, because if I replace a Text node with some html that include tags, for the next replacement/translation with will completely mess up the content of the element. Of course it is not be the same dirty replacement than before, it is a cleaner solution using the replaceChildren method.

I just had to create a sort of format for the library to create some tags and inserted them into the element. This also helped to recognize when to make a Text replacement or a complete replacement. For the moment this format doesn’t support nesting elements, probably that will be the next thing to add in the future if any person uses it for some strange reason. In the end the format looked something like this:

"rich-text": [
  {
    "value": "Normal text "
  },
  {
    "tag": "b",
    "value": "Bold text "
  },
  {
    "tag": "a",
    "value": "Link",
    "href": "https://www.google.com"
  }
]Code language: JSON / JSON with Comments (json)

Now I could fully replaced the script I had used in my site with this new one by replacing only the language files, and only adding a single line to my HTML.

<script src="https://cdn.jsdelivr.net/gh/gerardo-m/spat@master/dist/spat.min.js"></script>
Code language: JavaScript (javascript)

What’s next

Probably fixing errors, handling invalid scenarios and stuff, it all depends if somebody out there find this useful enough. If you want to try it visit the repo for instructions.

Tags :

Leave a Reply

Your email address will not be published. Required fields are marked *