Problems with dynamic loading in JavaScript

I am new to JavaScript and will learn by working on a clean JavaScript project that calculates math functions. Everything works well. Now, as the next step, I want to do multilingual messaging. The code should be able to load the appropriate language file at runtime. For a dynamic loading problem, I read and found solutions on web pages, like this one .

Before writing dynamic code, I downloaded it statically and the test code worked fine. The code I'm asking for help just makes a slight difference in loading the script element.

The code in which I ran into problems is the this.getString function, where it is not possible to access an element in a language file. In the line console.log (eval (language, tag)); I get the error message "Uncaught ReferenceError: de undefined".

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

Static test code that works is not included, where can I access the de element.

My question is: how to properly load a language file so that an accessible tag is available?

Thanks for the 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> 
+5
source share
3 answers

When you add a script tag to your document, it does not load synchronously. You need to wait for the file to load before you can use the code that was in it.

you can change your code to use script.onload callback:

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

but for this scenario, if you do not have many language strings, you might be best off loading them all statically.

+3
source

How to dynamically load a script file (the most basic version, there are also several options):

  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) . The first two arguments point to your file and folder. The final argument is a callback function. Once defined, this will be executed after the script tag completes the download and the script is available in the global scope. The script will be dynamically added to your page. If a script element is present on the page, this will be added before (to maintain a good rating). If it will not be added to the body. (this is only visual).

The callback component is the most interesting. Since your script will now be asynchronical , you will need to use a callback to tell your program that the necessary files are loading. This callback is triggered when the script file is loaded, so you won't get a script error.


Just a basic example of what I had in mind in my comment:

This is not the answer to your question, this is an alternative way (I think it’s better to manage). Pure Javascript (using XML)

XML file: language.xml Basic XML structure:

 <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 I've done:
I created a root element called a language. Inside this are written two language lines called l1033 for English and l1031 for German. Note that the letter precedes the letter code. XML will throw an error when a tag starts with a number. a CDATA used to prevent any problems with special characters.

Now loading will be done using 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 } } 

XML is now loaded. How to load lines 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 a function:

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

I found the correct answer to my question using information from GarethOwen. Here are the code changes I had to make:

 <!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> 
  • TestLanguage.html: body tag added

     <body onload="load()"> 
  • TestLanguage.js: 2a. Added the load () function requested by the HTML page:

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

2b. Using the global variable gCodes also in the output () function

  1. Language.js: To better verify everything, I made the code in the Language function a little more complicated by changing the line in the constructor in the Language (language) function to:

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

Thanks 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! 
0
source

All Articles