简体   繁体   English

JavaScript 动态加载的问题

[英]Problems with dynamic loading in JavaScript

I am a JavaScript newbie and learn by working on a pure JavaScript "project" that calculates mathematical functions.我是一个 JavaScript 新手,通过研究一个计算数学函数的JavaScript“项目”来学习。 It all works well.这一切都很好。 Now, as a further step, I want to make the messaging multilingual.现在,作为进一步的步骤,我想让消息传递多语言。 The code should be capable of loading the appropriate language file at runtime.代码应该能够在运行时加载适当的语言文件。 For the dynamic loading issue, I read and found solutions on Web pages like this one .对于动态加载的问题,我看,发现网页上的解决方案,像这一个

Before writing the dynamic code, I loaded it statically and the test code worked well.在写动态代码之前,我静态加载了它,测试代码运行良好。 The code I am asking for help about is just making the minor difference of loading a "script" element.我寻求帮助的代码只是加载“脚本”元素的细微差别。

The code where I run into problems is the this.getString function, where it is not possible to access the de element in the language file.我遇到问题的代码是this.getString函数,其中无法访问语言文件中的de元素。 At line console.log(eval(language, tag));在行console.log(eval(language, tag)); , I get the error message " Uncaught ReferenceError: de is not defined ". ,我收到错误消息“ Uncaught ReferenceError: de is not defined ”。

//File: Utils/Lang/js/FileUtils.js
function Language(language) {
    var __construct = function(dynamicLoad) {
        if (typeof language == 'undefined') {
            language = "en";
        }
        // Load the proper language file:
        loadFile("js/resources/lang.de.js");
        return;
    } ()

    this.getString = function(tag, strDefault) {
        console.log("getString(" + tag + ", " + strDefault + "): ");
        console.log("getString(...): document = " + document);
        console.log("getString(...): eval(" + language + ", " + tag + ") = ");
        console.log(eval(language, tag));
        var strReturn = eval('eval(language).' + tag);

        if (typeof strReturn != 'undefined') {
            return strReturn;
        } else {
            return (typeof strDefault != 'undefined') 
                ? strDefault
                    : eval('en.' + tag);
        }
    }
}

The static test code that works is not included, where I can access the de element.不包括有效的静态测试代码,我可以在其中访问 de 元素。

My question: How to load the language file properly so that the de tag is accessible?我的问题:如何正确加载语言文件以便de标签可访问?

Thank you for your help!感谢您的帮助!

 //File: Utils/Files/js/FileUtils.js function loadFile(filepathname) { var reference = document.createElement('script'); reference.setAttribute("type", "text/javascript"); reference.setAttribute("src", filepathname); if (typeof reference != 'undefined') { document.getElementsByTagName("head")[0].appendChild(reference); } console.log("loadFile(\\"" + filepathname + "\\"): document = " + document); } //File: Utils/Lang/js/resources/lang.de.js: de = { pleaseWait: "Bitte warten..." }; //File: Utils/Lang/js/resources/lang.en.js en = { pleaseWait: "Please wait..." }; //File: Utils/Lang/js/TestLanguage.js: function output() { console.log("output()"); var codes = ['de', 'en']; for (var i = 0; i < codes.length; i++) { var translator = new Language(codes[i]); var message = "output(): in " + translator.getLanguage() + ": "; message += translator.getString('pleaseWait'); console.log(message); } }
 <!--File: Utils/Lang/TestLang.html:--> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Test languages</title> <script type="text/javascript" src="../Files/js/FileUtils.js"></script> <script type="text/javascript" src="js/Language.js"></script> <script type="text/javascript" src="js/TestLanguage.js"></script> </head> <body> <button name="outputButton" onclick="output();">Click</button> <br>Please press [F12] so that you can see the test results. </body> </html>

When you add the script tag to your document, it is not loaded synchronously.将脚本标记添加到文档时,它不会同步加载。 You need to wait for the file to be loaded before you can use the code that was in it.您需要等待文件加载完毕,然后才能使用其中的代码。

you may be able to redesign your code to use a script.onload callback:您可以重新设计代码以使用 script.onload 回调:

var reference = document.createElement('script');
// ...
reference.onload = function() {
  alert("Script loaded and ready");
};

but for this scenario, if you don't have many language string you may be best to just load them all statically.但是对于这种情况,如果您没有很多语言字符串,您最好只静态加载它们。

How to dynamically load a script file (the most basic version, also there are multiple options to this):如何动态加载脚本文件(最基本的版本,也有多个选项):

   function loadScriptFile(scriptPath, jsFile, callBack)
   {
       var scriptTag = document.createElement("script"); //creates a HTML script element
       scriptTag.language = "JavaScript"; //sets the language attribute
       scriptTag.type = "text/javascript";
       scriptTag.src = scriptPath + jsFile + ".js"; //the source
       if (callBack)
       {
            scriptTag.onload = callback; //when loaded execute call back
       }
       var scriptTagParent = document.getElementsByTagName("script")[0];
       if (scriptTagParent)
       {
                scriptTagParent.parentNode.insertBefore(scriptTag, scriptTagParent);
       }
       else
       {
           document.body.appendChild(scriptTag);
       }
    }

How it works:这个怎么运作:

Run loadScriptFile("scripts", "math", startProgram) .运行loadScriptFile("scripts", "math", startProgram) The first two arguments will point to your file and folder.前两个参数将指向您的文件和文件夹。 The last argument is a callback function.最后一个参数是一个回调函数。 When defined this will be executed once the script tag has finished loading and the script is available in the global scope.定义后,这将在脚本标记加载完成并且脚本在全局范围内可用后执行。 The script will be dynamically added to your page.该脚本将动态添加到您的页面。 If there is a script element present on the page, this will be added before that (to keep the mark up nice).如果页面上存在脚本元素,则会在此之前添加(以保持标记良好)。 If not it will be appended to the body.如果不是,它将被附加到正文中。 (this is only visual). (这只是视觉效果)。

The callback part is the most interesting.回调部分是最有趣的。 Since your script will now be asynchronical , you'll need to use callback to tell your program that the necessary files are loaded.由于您的脚本现在将是asynchronical ,您需要使用回调来告诉您的程序加载了必要的文件。 This callback is fired when the script file is loaded, so you won't get script errors.加载脚本文件时会触发此回调,因此您不会收到脚本错误。


Just a basic example of what I meant in my comment:只是我在评论中的意思的一个基本示例:

This is not an answer to your question, it's an alternative way (I think it's better to manage).这不是您问题的答案,而是另一种方式(我认为最好进行管理)。 Pure Javascript (with help of XML)纯 Javascript(借助 XML)

XML-file: language.xml Basic XML structure: XML 文件:language.xml 基本 XML 结构:

<language>
    <l1033 name="english" tag="en-US">
        <id1000>
            <![CDATA[
                Hello World!
            ]]>
        </id1000>
    </l1033>
    <l1031 name="german" tag="de-DE">
        <id1000>
            <![CDATA[
                Hallo Welt!
            ]]>
        </id1000>
    </l1031>
</language>

What did I do:我做了什么:
I constructed a root element called language.我构建了一个称为语言的根元素。 Within that wrote two language strings called l1033 for English and l1031 for German.在里面写了两个语言字符串, l1033是英语的l1031和德语的l1031 Note that a letter is prepended before the language code.请注意,在语言代码之前添加了一个字母。 XML will throw an error when a tag starts with a digit.当标签以数字开头时,XML 将抛出错误。 a CDATA block is used to prevent any problems with special characters. CDATA块用于防止出现任何特殊字符问题。

Now the loading will be done by AJAX:现在加载将由 AJAX 完成:

var xmlLoader = new XMLHttpRequest();
xmlLoader.onreadystatechange = trackRequest; //event to track the request, with call back
xmlLoader.open("get", "language.xml", true); //set asynchronous to true
xmlLoader.send(null);

function trackRequest()
{
   if (this.status == 200 && this.readyState == 4) //all is good
   {
      globalLanguageFile = this.responseXML;
      startProgram(); //fictive function that starts your program
   }
}

Now the XML is loaded.现在已加载 XML。 How to load strings from it?如何从中加载字符串?

function loadLanguageString(code, id, fallback)
{
    var word = fallback;  
    if (globalLanguageFile.getElementsByTagName("l"+code).length > 0)
    {
        if (globalLanguageFile.getElementsByTagName("l"+code).[0].getElementsByTagName("id"+id).length > 0)
        {
            //found the correct language tag and id tag. Now retrieve the content with textContent.
            word = globalLanguageFile.getElementsByTagName("l"+code).[0].getElementsByTagName("id"+id)[0].textContent;
        }
    }

    return word; //when failed return fall back string
}

How to call the function:如何调用函数:

loadLanguageString(1031, 1000, "Hello World!");

I found the right answer to my question using the info from GarethOwen.我使用 GarethOwen 提供的信息找到了我问题的正确答案。 Here are the code modifications I had to do:以下是我必须做的代码修改:

 <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Test languages</title> <script type="text/javascript" src="../Arrays/js/ArrayUtils.js"></script> <script type="text/javascript" src="../Files/js/FileUtils.js"></script> <script type="text/javascript" src="../Logic/js/LogicalUtils.js"></script> <script type="text/javascript" src="js/LanguageUtils.js"></script> <script type="text/javascript" src="js/TestLanguageUtils.js"></script> </head> <!-- body onload="load(null, '../Maths/js/resources')" --> <body onload="load();"> <button onclick="output();">Click</button><br> Please press [F12] so that you can see the test results. </body> </html>

  1. TestLanguage.html : Augmented the body tag TestLanguage.html : 增加了 body 标签

    <body onload="load()">
  2. TestLanguage.js : 2a. TestLanguage.js :2a。 Added the load() function requested by the HTML page now:现在添加了 HTML 页面请求的load()函数:

     var gCodes = ['de', 'en', 'tr']; function load() { console.log("load()"); for (var i = 0; i < codes.length; i++) { new Language(codes[i]); } }

2b. 2b. Using the global gCodes variable also in the output() functionoutput()函数中也使用全局gCodes变量

  1. Language.js : To test the whole better, I made the code in the function Language a little bit more elaborate by changing the line in the constructor in function Language(language) to: Language.js :为了更好地测试整体,我通过将函数 Language(language) 中构造函数中的行更改为:

     // Load the proper language file: if (eval("gLoaded.indexOf('" + language + "') < 0")) { loadFile("js/resources/lang." + language + ".js"); gLoaded[gLoaded.length] = language; }

Thank you for your support!感谢您的支持! :-) :-)

 //Lang/js/Lang.js: "use strict"; /** * Object for multilingual message handling. * * @param language */ function Language(language) { var __construct = function(dynamicLoad) { if (typeof language == 'undefined') { language = "en"; } // Load the proper language file: switch (language) { case "de": loadFile("js/resources/lang.de.js"); break; case "tr": loadFile("js/resources/lang.tr.js"); break; default: loadFile("js/resources/lang.en.js"); } return; }() /** * Returns the language of that object. * * @returns The language */ this.getLanguage = function() { var strLanguage; switch (language) { case "de": strLanguage = "German"; break; case "tr": strLanguage = "Turkish"; break; default: strLanguage = "English"; } return strLanguage; } /** * Returns the language code of that object. * * @returns The language code */ this.getString = function(tag, strDefault) { var strReturn = eval('eval(language).' + tag); if (typeof strReturn != 'undefined') { return strReturn; } else { return (typeof strDefault != 'undefined') ? strDefault : eval('en.' + tag); } } } //Lang/js/TestLang.js: "use strict"; var gCodes = ['de', 'en', 'tr']; function load() { console.log("load()"); for (var i = 0; i < gCodes.length; i++) { new Language(gCodes[i]); } } /** * Object for multilingual message handling. * * @param language */ function output() { console.log("output()"); for (var i = 0; i < gCodes.length; i++) { var translator = new Language(gCodes[i]); var message = "output(): in " + translator.getLanguage() + ": "; message += translator.getString('pleaseWait'); console.log(message); } } //Utils/Files/js/FileUtils.js: "use strict"; /** * Object with file utilities * * @param filepathname */ function loadFile(filepathname) { var methodName = "loadFile(" + filepathname + "): " var reference = document.createElement('script'); reference.setAttribute("type", "text/javascript"); reference.setAttribute("src", filepathname); if (typeof reference != 'undefined') { document.getElementsByTagName("head")[0].appendChild(reference); } reference.onload = function() { console.log(methodName + "onload(): Language script loaded and ready!"); } }

Here is the console output:这是控制台输出:

Here is the output:
load()
loadFile(js/resources/lang.de.js): onload(): Language script loaded and ready!
loadFile(js/resources/lang.en.js): onload(): Language script loaded and ready!
loadFile(js/resources/lang.tr.js): onload(): Language script loaded and ready!
output()
output(): in German: Bitte warten...
output(): in English: Please wait...
output(): in Turkish: Lütfen bekleyiniz...
loadFile(js/resources/lang.de.js): onload(): Language script loaded and ready!
loadFile(js/resources/lang.en.js): onload(): Language script loaded and ready!
loadFile(js/resources/lang.tr.js): onload(): Language script loaded and ready!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM