首页 > 解决方案 > 从没有服务器的 HTML Head 读取 JSON 文件

问题描述

我得到了一些翻译的 json 文件。我想在 JS 文件中使用这个文件来翻译一些字符串。但我没有一个好的解决方案来加载这个文件和数据。

到目前为止我得到的是我的 HTML 文件:

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

JSON文件:

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

还有我的 JS 文件:

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);

但问题是,翻译文件被读到很晚,在构造函数中我不能使用这部分,或者我做错了什么?

那么加载和读取存储在本地的 json 文件的最佳方法是什么。

我不想要服务器或其他任何东西,只想要可以在所有现代浏览器上运行的纯 Javascript。因为这是用户的导出,他们应该能够观看此页面而无需安装任何东西或需要互联网连接

标签: javascriptjsonserverlessreadfile

解决方案


如果您想坚持使用同步 XHTTPRequest(不推荐),那么您只需要更改send()函数的顺序,在附加事件侦听器之前调用它onreadystatechange,它必须在之后调用:

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

它会起作用,但会在控制台中显示警告[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.

建议在 JavaScript 中使用异步函数。异步构造函数不起作用,因此有一些模式可以帮助解决这个问题:https ://stackoverflow.com/a/43433773/3075373

例如,最好使用.init()这样的函数:

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 评论:

例如,可以添加另一个文件languages.js

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

export default languages;

然后在你的主脚本中添加type="module",以便你可以导入另一个 js 文件(注意:它主要在现代浏览器中工作,通常它是在webpack等的帮助下完成的,以帮助旧浏览器,但它完全是另一个主题)

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

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

您也可以简单地将顶部的对象粘贴languages到主脚本中,然后无需导入另一个 js 文件。


推荐阅读