Home > database >  Read JSON File from HTML Head without Server
Read JSON File from HTML Head without Server

Time:10-19

I got a json file for some translations. I would like to use this file in a JS file to translate some strings. But i do not get a good solution to load this file and data.

What i got so far is in my HTML File:

<script type='application/json' src='lang/translations.json'></script>
<script src="Javascript/translator.js" charset="UTF-8"></script>

JSON File:

{
  "language": {
    "en": {
      "closure": "Closure",
      "documents": "Documents",
      "overview": "Overview"
    },
    "de": {
      "closure": "Abschluss",
      "documents": "Dokumente",
      "overview": "Übersicht"
    }
  }
}

And my JS file:

let docLanguage = document.documentElement.lang;
let browserLanguage = navigator.language.substr(0, 2);
let lang = docLanguage ? docLanguage : browserLanguage;
let texts;

const Http = new XMLHttpRequest();
const url = "lang/"   lang   ".json";

Http.open("GET", url, false);
Http.send();
Http.onreadystatechange = function () {
    texts = JSON.parse(Http.responseText);
    return texts;
}

let getJson = jQuery.getJSON('lang/'   lang   '.json', {format: "json", async: false})
    .done(function (data) {
        // texts = data;
        return data;
    }).fail(function () {
        console.log('empty');
    });

class translator {
    constructor(lang) {
        this.lang = lang;
        this.translations = texts;
    }

    _(keyName) {
        // return texts.get(keyName);
    //  todo get by keyName
    }

    transHtml(attribute = 'data-lang') {
        let htmlElements = document.querySelectorAll('['   attribute   ']');
        for (let htmlElement of htmlElements) {
            let keyName = htmlElement.getAttribute(attribute);
            htmlElement.textContent = this._(keyName);
        }
    }
}

var translate = new translator(lang);

But the Problem is, that the translations file is read to late and in the constructor i can not use this parts, or am i doing something wrong?

So what is the best way to load and read a json file which is stored local.

I do not want a server or anything else, only pure Javascript which can run on all modern Browsers. Because this is an Export for users and they should be able to just watch this page without the need of installing anything or the need of a internet connection

CodePudding user response:

If you want to stick with synchronous XHTTPRequest (not recommended) then you need to just change the order of send() function, you call it before you attach onreadystatechange event listener, it has to be called after:

Http.open("GET", url, false);
Http.onreadystatechange = function () {
    texts = JSON.parse(Http.responseText);
    return texts;
}
Http.send(); // called after onreadystatechange

It will work but shows warning in console [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.

It's recommended to use asynchronous funtions in JavaScript. Async constructor won't work so there are patterns to help with that: https://stackoverflow.com/a/43433773/3075373

For example it would be better to use .init() function like this:

let docLanguage = document.documentElement.lang;
let browserLanguage = navigator.language.substr(0, 2);
let lang = docLanguage ? docLanguage : browserLanguage;

class translator {
    constructor(lang) {
        this.lang = lang;
    }

    init(cb) {
        jQuery.getJSON('lang/'   this.lang   '.json', { format: "json" })
        .done(result => {
            this.translations = result;
            cb.bind(this)();
        })
        .fail(err => console.log(err))
    }

    _(keyName) {
        // return texts.get(keyName);
    //  todo get by keyName
    }

    transHtml(attribute = 'data-lang') {
        let htmlElements = document.querySelectorAll('['   attribute   ']');
    
        for (let htmlElement of htmlElements) {
            let keyName = htmlElement.getAttribute(attribute);
            htmlElement.textContent = this._(keyName);
        }
    }
}

var translate = new translator(lang);
translate.init(() => {
    // inside you can use methods that rely on translations being loaded e.g:
    translate.transHtml();
})

@Answer to comment:

It's possible to add for example another file languages.js

const languages = {
    "language": {
        "en": {
        "closure": "Closure",
        "documents": "Documents",
        "overview": "Overview"
        },
        "de": {
        "closure": "Abschluss",
        "documents": "Dokumente",
        "overview": "Übersicht"
        }
    }
}

export default languages;

and then in your main script add type="module" so that you can import another js file (note: it will work mostly in modern browsers, usually it's done with help of webpack etc. to help with older browsers but it's whole another topic)

<script type="module">
import lngs from './languages.js'

let docLanguage = document.documentElement.lang;
...
...
...
rest of script

You can simply also paste languages object at the top into your main script and then there will be no need to import another js file.

  • Related