在没有服务器的情况下从 HTML 头读取 JSON 文件

Read JSON File from HTML Head without Server

我得到了一些翻译的 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。因为这是针对用户的导出,他们应该能够只观看此页面而无需安装任何东西或需要互联网连接

如果你想坚持使用同步 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中使用异步函数。 异步构造函数将不起作用,因此有一些模式可以帮助解决这个问题:

例如,最好使用这样的 .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();
})

@回复评论:

例如可以添加另一个文件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[= 的帮助下完成的40=] 等以帮助旧版浏览器,但这完全是另一个话题)

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

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

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