Last Updated:

Creating Multilingual Web Applications with JSTemplater 1.0 Alfa

In this article, I would like to talk about multilingual applications, namely creating them in the context of JavaScript and XHTML technology, without using arbitrary server technologies.

Each of us who has once directly encountered the development of multilingual applications knows all their versatility and, in some cases, the ambiguity of creation. For example, sometimes a client needs to send, for example, a questionnaire in which the client would indicate what exactly he wants, how he wants it, and what he can give for it.

Here the question arises: "And if the client is a foreigner?", That is, already from this question, another question appears: "What is the most rational way to implement multilingualism?". Of course, you can initially translate the document into several languages, but then send one of them to the customer. Yes, this is certainly permissible, and is most used in the context of modern web studios and other companies in one way or another conducting a dialogue with customers.

I chose a different approach, which I consider a little more flexible and practical, and in no way inferior to the "manual" division into languages. Its essence lies in the introduction of a templating system, and the conversion of language units into template variables, which will later be replaced by the same language units, but related to a different language. An example of a similar mechanism can be observed everywhere in systems that somehow use patterning in the interface or in the internal implementation of the system as a whole. So striking examples of templating systems can serve as such systems as PatTemplaters, Smarty and so on. In them, the resulting data is formed on the basis of some incoming data (template variables) that are "substituted" into the template, after which they are executed in the context of a given set of algorithmic template logic, and returned in the form of processed text.

In our case, everything is similar, but the JSTemplater 1.0Afla parser is designed to function on the client side, and as input it takes not the text of the template, but the entire current HTML document, starting with the tag <body>, and downloading the place of the method call to render the service constructs that were found in the HTML document.

But we are not talking about the subject of the JSTemplater 1.0Alfa parser, but about how to use it in practice. But for this you need to at least download it, for this go to the following address: http://e-code.tnt43.com/sources/jsTemplater.zip (ZIP-packed archive).

To connect a parser to your document, simply connect the JS script that is archived to your document in the <HEAD> section. Next, you need to specify the id of the <body tag>, and set its value to "body". This is required to access the element nodes of the XHTML document.

Just as fundamentally, in order for the document to be processed correctly, is to call the JSTemplater.init() function just before the closing tag </body>, which is necessary for the parser to receive all the nodes of the document, and not just those that have managed to load at the present time.

Well, here's the skeleton of the minimal application:

Code Listing 1.1

  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
	  <meta http-equiv="content-type" content="text/html;
          charset=windows-1250">
	  <meta name="generator" content="PSPad editor, www.pspad.com">
	  <title></title>
	  <script type='text/javascript' src='jsTemplater.js'></script>
  </head>
  <body id='body'>
		
		<script type='text/javascript'>
		<!--
		    JSTemplater.init();
		-->
		</script>
  </body>
</html>

So, in order not to dwell on the description of the template engine technology anymore, I will give a list of functions that we will use in the future, as well as their semantics:

FunctionExplanation
JSTemplater.init()The function after the call begins processing. You must call </body before the closing tag>
JSTemplater.registerLib(src, type)Connects the external library to the current document. Library - src file, type format (text/javascript, text/css). This is added to the <head section>
JSTemplater.assignVariable(name,value)Declare a template variable named name and value value
JSTemplater.makeArray(name)Create name array
JSTemplater.append2Array(name, value)Add a scalar value to the name array
JSTemplater.append2ArrayIndex(arr, name,value)Add a value element, of scalar type, to the name array in the arr array (two-dimensional array)
JSTemplater.loadLibs()Load the registered (see JSTemplater.registerLib) libraries.

Well, now let's talk about multilingualism. In order to reveal the topic of the article, I propose to consider the real situation with some form intended for customers, with two conditions: it is available in 3 languages, it must be focused on processing on the client interface side.

Now, we will create a small questionnaire that will contain: 5 information fields (field name, input field), 3 buttons for switching between languages (Russian, English, French).

It will be the simplest:

Code Listing 1.2

<div class='langs'>
<button onclick='setLang("ru");'>Russian!</button>
<button onclick='setLang("en");'>English !</button>
<button onclick='setLang("fr");'>Francais!</button>
</div>
<form action='http://somehost.somedomain/formProceed' method='post'>
Enter your name: <input type='text' name='first'/><br/>
How did you hear about our company? <br/>
<input type='text' name='wayf'><br/>
How do you rate the quality of the services we provide?<br/>
<select name='quality'>
<option value='0'>Great</option>
<option value='1'>Good</option>
<option value='2'>Satisfactory</option>
<option value='3'>Mediocre</option>
<option value='4'>Bad</option>
</select><br/>
<input type='submit' name='send' value='Submit information to us'/>
</form>

As you can see, in our case we have a lot of text data that can be divided into separate string constants according to their semantics, and some after a similar cast are distributed relative to an array of values (an example of this is the value of the "quality" list).

Each variable text value of the document will correspond to a variable value, which is usually either placed in the value of the control name opposite it with the addition of the postfix "_l", or simply semantically close to this name.

So, we will have the following constants:

  1. lang {en, fr, ru} //array with inscriptions to the language change buttons
  2. yname //text next to the yname element
  3. wayf //similar
  4. quality {0,1,2,3,4} //array of quality rating values

It should also be noted that some constants have the same meaning(s) relative to the language, while others are declared relative to the currently chosen language. In our case, we will use the switch(){default:break;} operator and a set of case statements for this purpose, which will simply declare constants depending on the selected language.

And how will we determine which language is chosen? Through QUERY_STRING.

Here are the setLang(val:String):Void: and getLang():String functions that will be used to set/get the current language parameter.

Code Listing 1.3

function setLang(value){
document.location.href='?lang='+value;
}

function getLang(){
if(document.location.search){
lang=document.location.search.split('=');
lang=lang[1];
}else{
lang='en';
}
return language;
}  

Now we can directly specify the language schemes:

Code Listing 1.4

function definitions(){
           JSTemplater.assignVariable("lang",getLang());
JSTemplater.makeArray("quality");
JSTemplater.makeArray("lang");
JSTemplater.append2ArrayIndex("lang","ru","I want Russian !");
JSTemplater.append2ArrayIndex("lang","en","I'm wanting it in English !");
JSTemplater.append2ArrayIndex("lang","fr","Je veux en francais!");
switch(getLang()){
case 'en':
//Russian language scheme
JSTemplater.assignVariable("yname","Enter your name");
JSTemplater.assignVariable("wayf","How did you hear about our company?");
JSTemplater.append2Array("quality","Good");
JSTemplater.append2Array("quality","Excellent");
JSTemplater.append2Array("quality","Mediocre");
JSTemplater.append2Array("quality","Bad");
break;
case 'en':
//English language scheme
JSTemplater.assignVariable("yname","Enter your name");
JSTemplater.assignVariable("wayf","Where did you find us?");
JSTemplater.append2Array("quality","Good");
JSTemplater.append2Array("quality","very good");
JSTemplater.append2Array("quality","Average");
JSTemplater.append2Array("quality","Bad");
break;
case 'fr':
//French language scheme
break;
}
}

This listing demonstrates how to specify text constants, the value of which will change the service constructs in the source code of the template, after accessing the init() function.

As you can see, everything is extremely simple. And for greater clarity, we will now move on to the source code of the template that will be processed:

Code Listing 1.5

 //....
<body id='body'>
The value of the current language scheme identifier: <strong>{^lang^}</strong>
<div class='langs'>
<button onclick='setLang("ru");return false;'>{^lang{ru}^}</button>
<button onclick='setLang("en");return false;'>{^lang{en}^}</button>
<button onclick='setLang("fr");return false;'>{^lang{fr}^}</button>
</div>
<form action='http://somehost.somedomain/formProceed' method='post'>
{^yname^}: <input type='text' name='first'/><br/>
{^wayf^} <br/>
<input type='text' name='wayf'><br/>
{^lang{quality_label}^}<br/>
<select name='quality'>
<option value='0'>{^quality{0}^}</option>
<option value='1'>{^quality{1}^}</option>
<option value='2'>{^quality{2}^}</option>
<option value='3'>{^quality{3}^}</option>
</select><br/>
<input type='submit' name='send' value='Submit information to us'/>
</form>
//...

That's it. Our application is fully functional, and quite correctly works, while the extension is not a particular problem.

Well, for those who are too lazy to read the JSTemplator (http://e-code.tnt43.com/specs/t0.005.pdf) design specification version 1.0, here is the syntax of the basic constructs:

MaskName
(open_bracket)+(.*)(close_bracket)+Accessing a variable
(open_bracket)+((.*)\{([0-9]*)\})(close_bracket)+Accessing the Numeric Index of an Array
(open_bracket)+((.*)\{(.*)\})(close_bracket)+Accessing the Literal Index of an Array

In this case, the open_bracket and close_bracket the default "{^" and "^}", and can be changed using a special function of the JSTemplater library.