Lingue e unità di misura con AJAX e XML

Pubblicato da Nicola Rainiero il 18-11-2012 (aggiornato il 19-11-2012)

Una caratteristica che ritengo utile dare al mio programma per le reti bianche è la possibilità di cambiare e aggiungere nuove lingue cliccando su un apposito selettore ed editando un semplicissimo file di testo. Allo stesso modo trovo confortevole poter fare lo stesso con le unità di misura e con alcune loro derivate (come nel caso della portata in m3/s o litri/s). Mostrerò i risultati raggiunti con AJAX e XML.

Anticipo subito che non rappresentano la versione definitiva e ho già notato che hanno un difetto: quando vado ad aggiungere al DOM nuovo codice HTML non viene processato!! Ma credo che con un po' di pratica javascript e ottimizzando il tutto con opportune funzioni e richiami, si possa superare questo inconveniente rendendo il tutto più performante e fluido.

In questo articolo descriverò come ho affrontato il problema e pubblicherò il codice usato. L'esempio funzionante invece è raggiungibile a questo indirizzo.

Multi-lingua

Ho preso spunto da questa guida: How to make your site Multilingual using XML and jQuery e ho adattato il tutto a svolgere queste operazioni:

  1. lettura dell'eventuale prefisso della lingua attraverso il link al programma (url?language=prefisso_della_lingua) e definizione della variabile language, se non viene trovato nulla si definisce l'inglese (en) come valore di default;
  2. costruzione dal file language.xml delle voci che compongono il menu a tendina per cambiare il valore della variabile language;
  3. ricerca nel file XML di tutti gli id presenti e sostituzione del testo relativo alla lingua scelta con quello presente nelle omonime classi del DOM.

Il file language.xml l'ho scritto in questo modo:

<?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>

Mentre il codice jQuery è il seguente:

// 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

Unità di misura

In questo caso il sistema di riferimento è quello Internazionale (il SI), tutti quelli aggiuntivi conterranno il relativo fattore moltiplicativo rispetto ad esso, per esempio in m_mq_mc (il SI) 1 metro ha fattore 1, in km_ha_l 1 metro ha invece 0,001.

Le operazioni sono le seguenti:

  1. costruzione dal file measurement.xml delle voci che compongono il menu a tendina per aggiornare tutte le grandezze presenti con rispettive nuove unità di misura;
  2. inizializzazione di tutte le matrici (ho usato quanto suggerito in questa discussione) che contengono i valori presenti in opportune classi CSS (per esempio per la lunghezza l'ho definita con lnumber);
  3. conversione di tutti i descrittori mediante moltiplicazione del valore salvato nelle matrici e semplice sostituzione del descrittore dell'unità di misura (sempre per la lunghezza ho usato lunit).

Il file measurement.xml l'ho scritto in questo modo:

<?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&lt;sup&gt;2&lt;/sup&gt;">1</m_mq_mc>
<km_ha_l value="ha">0.0001</km_ha_l>
</unit>
<unit id="flow">
<m_mq_mc value="m&lt;sup&gt;3&lt;/sup&gt;/s">1</m_mq_mc>
<km_ha_l value="l/s">1000</km_ha_l>
</unit>
</units>

Mentre il codice jQuery è il seguente:

// 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

Ammetto che al momento è un po' macchinoso e laborioso, ma spero di migliorarlo, riducendo il tutto a poche funzioni adattabili a tutte le diverse unità di misura presenti e soprattutto che tengano conto anche delle nuove misure che viva via verranno aggiunte, soprattutto quando si definiranno i tronchi della rete.

Se volete vedere come funziona il tutto potete collegarvi qui, mentre qui ho compresso tutti i file usati: storm_sewer.zip. Come sempre ogni vostro aiuto, discussione, suggerimento e correzione è bene accetto!!




Potrebbero interessarti anche:

Nicola Rainiero

Ingegnere civile specializzato in geotecnica con l'ambizione di facilitare la propria attività lavorativa usando e creando software libero per un sapere condiviso e collettivo. Mi occupo anche di energie rinnovabili ed in particolare di geotermia a bassa entalpia. Sono da sempre appassionato di web design e modellazione 3D.