More languages and units with AJAX
An interesting feature for my future Storm Sewer software will be the ability to change and add new languages, simply clicking on a selector and editing a text file. In a similar way it can be the same with the units of measurement (for example changing the flow from m3/s to litre/s). I will show you my achieved results using AJAX and XML.
Well, at this moment they are incomplete and I found a bug: after I added new HTML code to DOM, this doesn't be translated!! But I'm going to improve my skills in Javascript and if I create functions and callbacks, I think that it will possibile to remove this inconvenient.
In this short article I will describe how I analyzed the problem and I will publish the used code. You can see the demo here.
Multi-lingual
My main reference is this tutorial: How to make your site Multilingual using XML and jQuery and I have adapted it to the following operations:
- read the url looking for a language variable (i.e. url?language=language_prefix) and definition of the language internal variable, if it doesn't exist this becomes English (en);
- from the reading of language.xml file, it builds items adding them in the selector button of the language, and changes the default language variable, if you select another language;
- search in XML file of all the ID and change the text inside the homonym CSS class in the DOM with the current language.
Here is my language.xml:
<?xml version="1.0" encoding="UTF-8"?>
<translations>
<languages>
<language value="en">English</language>
<language value ="it">Italiano</language>
</languages>
<translation id="lang_title">
<en>Storm sewer web-app by Nicola Rainiero /-- rainnic.altervista.org --\</en>
<it>Fognatura bianca web-app di Nicola Rainiero /-- rainnic.altervista.org --\</it>
</translation>
<translation id="lang_change">
<en>Change the language</en>
<it>Cambia lingua</it>
</translation>
<translation id="units_change">
<en>Change the default units of measurements</en>
<it>Cambia le unità di misura</it>
</translation>
<translation id="length">
<en>length </en>
<it>lunghezza </it>
</translation>
<translation id="lang_method">
<en>Linear method</en>
<it>Metodo dell'invaso</it>
</translation>
</translations>
While here is my jQuery code:
// TRANSLATIONS
// jquery for populate select of languages
$(document).ready(function(){
// check if exist a language variable in url
if(window.location.search.length) {
language = window.location.search.substr(10); // query string exists
} else {
language = 'en'; // no query string exists
} // end if
// read language.xml and put all the existent languages
$.ajax({
type: "GET",
url: "language.xml",
dataType: "xml",
success: function(xml) {
var select = $('#language');
$(xml).find('languages').each(function(){
$(this).find('language').each(function(){
var value = $(this).attr("value");
var title = $(this).text();
if (value == language) {
select.append('<option value="'+ value +'" selected=\"selected\">'+title+'</option>');
} else {
select.append('<option value="'+ value +'">'+title+'</option>');
}
}); // end language
}); // end languages
// function to change the default language
function displayVals() {
var singleValues = $('#language').val();
var language = singleValues;
var url=('http://' + window.location.hostname + window.location.pathname + '?language=' + language);
window.location.replace(url);
} // end function
$('#language').change(displayVals);
// translation of all id starting with lang_
$(xml).find('translation').each(function(){
var id = $(this).attr('id');
var text = $(this).find(language).text();
$("." + id).html(text);
}); // end function
} // end functio(xml)
}); // end ajax
}); // end jquery
// END TRANSLATIONS
Units of measurement
In this case the International System of Units (i.e. SI) is the default system, the others will describe with a factor of conversion, for example if I define another system with the unit of length in km, then this ratio becomes 0.001 (because 1 m = 0.001 km).
The code ran the following operations:
- from the reading of measurement.xml file, it builds items adding them in the selector button of the units, and changes the default variable, if you select another units of measurements;
- initialization of all numerical arrays (according to what I read in this discussion), these arrays contain the values defined in specific CSS classes (for example the length is lnumber);
- conversion of all numeric descriptors through a moltiplication of the specific ratio and change of the unit label described by a CSS class (for example the length unit is lunit).
Here is my measurement.xml:
<?xml version="1.0" encoding="UTF-8"?>
<units>
<measurements>
<measurement value="m_mq_mc">m_mq_mc</measurement>
<measurement value="km_ha_l">km_ha_l</measurement>
</measurements>
<unit id="length">
<m_mq_mc value="m">1</m_mq_mc>
<km_ha_l value="km">0.001</km_ha_l>
</unit>
<unit id="surface">
<m_mq_mc value="m<sup>2</sup>">1</m_mq_mc>
<km_ha_l value="ha">0.0001</km_ha_l>
</unit>
<unit id="flow">
<m_mq_mc value="m<sup>3</sup>/s">1</m_mq_mc>
<km_ha_l value="l/s">1000</km_ha_l>
</unit>
</units>
While here is my jQuery code:
// UNITS OF MEASUREMENT
// jquery for populate select of measurements
$(document).ready(function(){
// read measurement.xml and put all the existent units
$.ajax({
type: "GET",
url: "measurement.xml",
dataType: "xml",
success: function(xml) {
// read xml units id to populate option START
var select = $('#unit');
$(xml).find('measurements').each(function(){
$(this).find('measurement').each(function(){
var value = $(this).text();
if (typeof def_unit === 'undefined') {
def_unit = 'm_mq_mc';
}
if (value == def_unit) {
select.append('<option value="'+ value +'" selected=\"selected\">'+value+'</option>');
} else {
select.append('<option value="'+ value +'">'+value+'</option>');
}
}); // end measurement
}); // end xml measurements
// read xml units id to populate option END
//
// end option reading
// change the selected units of measurement START
$('#unit').change(function() {
var id = $(this).children(":selected").attr("value"); // id = m_mq_mc, etc.
def_unit = id;
// ... convert the measures START
if (typeof Lnumber === 'undefined') { // initialize the array wthin length and other measures
Lnumber = $('html').find('.lnumber').map(function() { return $(this).text(); }).get();
// can follow new arrays for other class: surface, flow, etc.
} // end if
//
$(xml).find('unit').each(function(){ // read XML with the selected id = m_mq_mc, etc.
var id = $(this).attr('id');
var value = $(this).find(def_unit).attr('value');
var text = $(this).find(def_unit).text();
// a test with lnumber class = length number format
$('.lnumber').each(function(indice){
if (id == 'length') {
ratio = parseFloat(text);
var convert = Lnumber[indice] * ratio;
$(this).text(convert);
}
}); // end function lnumber
// a test with lunit class = unit of measurement format
$('.lunit').each(function(){
if (id == 'length') {
$(this).text(value);
}
}); // end function lunit
}); // end function unit
// ... convert the measures END
//
//
}); // end function unit
// change the selected units of measurement END
} // end xml
}); // end ajax
}); // end jquery
// END UNITS OF MEASUREMENT
At this moment my solution is a little complicated, but I hope to improve and simplified it.
If you want to see the demo click here, while I put all files here: storm_sewer.zip. As usual I accept with pleasure any help, hint, correction, and so on!!!
Add new comment