|
|
Ho voluto mettere alla prova quanto ho esposto. In particolare l'ultima soluzione che mi ha fornito l'amico programmatore. E quale 'laboratorio' migliore di Califfo per fare una prova simile?
Ecco il primo incoraggiante risultato:
Ho creato una voce di menù che permette la scelta del linguaggio desiderato (cui fa da 'doppio' nel codice una variabile globale lang, settata a 0=linguaggio default, 1=inglese, 2=poi si vedrà....).
Poi con un normale editor di testo (Notepad) ho creato un file con una serie di doppie righe, ad esempio:
CODICE Apri Open Stampa Print Salva Save
E così via. Quindi un file di 'stringhe' in cui nelle righe dispari c'è la rappresentazione in italiano, nelle pari la corrispondente stringa in inglese. Ho chiamato questo file Lng_EN.clx
Poi ho dichiarato la seguente struttura dati:
CODICE struct strlanguage { char orgnstr[250]; char tradstr[250]; };
Ovvero una variabile che prima o poi dovrà contenere la riga dispari (orgnstr) e pari (tradstr) lette dal file suddetto (prima limitazione: 250 caratteri al massimo per singola riga scritta nel file).
Quindi ho creato due funzioni. Una 'generale' e che va eseguita all'avvio del programma ed ogni volta che l'utente modifica la scelta della lingua tramite apposito comando, ed una 'particolare' che esegue materialmente la traduzione di una stringa alla volta.
La funzione 'generale' che ho battezzato traduttore(), apre il file di testo con le varie stringhe, e si occupa di memorizzarle in un vettore di variabili struct strlanguage. Fatto questo, la funzione ha lo 'immane' compito di tradurre tutte le didascalie di qualsiasi finestra di dialogo (anche la principale) del programma, utilizzando la funzione 'particolare' che ho battezzato translate().
Cominciamo a vedere il funzionamento della prima funzione, in linguaggio C:
CODICE void traduttore() { FILE *fp; struct strlanguage *stringhe; int nstringhe=0; char buffer[500],filelanguage[500];
stringhe=(struct strlanguage *) calloc(nstringhe+1,sizeof(struct strlanguage));
/* Seleziona il file corretto in funzione della lingua scelta dall'Utente */ if (lang==ITA) strcpy(filelanguage," "); if (lang==ENG) sprintf (filelanguage,"%sLng_EN.clx",ExtractFilePath(Application->ExeName).c_str());
/* Apre il file e se esiste carica in memoria tutte le stringhe in esso contenute */ fp=fopen(filelanguage,"r");
if (fp!=NULL) { do { fgets(stringhe[nstringhe].orgnstr,250,fp); stringhe[nstringhe].orgnstr[strlen(stringhe[nstringhe].orgnstr)-1]='\0';
fgets(stringhe[nstringhe].tradstr,250,fp); stringhe[nstringhe].tradstr[strlen(stringhe[nstringhe].tradstr)-1]='\0';
nstringhe++; stringhe=(struct strlanguage *) realloc(stringhe,(nstringhe+1)*sizeof(struct strlanguage)); } while (feof(fp)==NULL);
}
fclose (fp);
/* La funzione continua traducendo le varie stringhe */ . . . /* Tradotte tutte le stringhe libera la memoria occupata da stringhe */ free(stringhe); }
Quindi per prima cosa la funzione, interrogando la variabile lang, va ad aprire il file con le stringhe tradotte nel linguaggio desiderato. Il nome del file nel caso di lingua standard (lang=ITA, o che è lo stesso: lang=0) viene posto pari a " " proprio per non far leggere nulla (il file non esiste e il puntatore al file, la variabile fp, varrà NULL). Se il file non esiste (cosa che potrebbe verificarsi anche nel caso di lingua inglese perchè per errore si è cancellato il file Lng_EN.clx) il valore della variabile nstringhe sarà 0 (è cosa che viene utilizzata dalla funzione 'particolare').
Se invece l'apertura del file ha esisto positivo, si comincia a leggere il suo contenuto cominciando a memorizzare i dati in memoria tramite la una variabile di tipo struct strlanguage di nome stringhe che viene allocata dinamicamente e la cui dimensione viene aumentata ad ogni record (voce originale e voce tradotta) che viene letto e memorizzato (con conseguente incremento anche della variabile nstringhe).
Poichè per la lettura ho utilizzato una funzione di basso livello (fgets()) questa mi legge anche il carattere 'a capo' '\n', che sono costretto a sostituire con il carattere '\0' che in C significa "fine della stringa".
A questo punto la funzione traduttore() conterrà una serie infinita di righe di codice come questa:
CODICE FinPrinc->MainMenu1->Items->Items[0]->Items[0]->Caption=translate("Nuovo",stringhe,nstringhe);
Questa riga in particolare traduce il termine "Nuovo" del menù a tendina di Califfo utilizzando la seconda funzione, translate():
CODICE char *translate(char *original,struct strlanguage *stringhe,int nstringhe) { int register k;
for (k=0;k<=nstringhe-1;k++) { if (strcmp(original,stringhe[k].orgnstr)==0) return(stringhe[k].tradstr); }
return(original); }
Questa funzione non fa altro che confrontare la stringa data come primo parametro (original) con quelle memorizzate nel campo orgnstr del vettore stringhe che le viene fornito come puntatore, e questo per tutte le righe del vettore stringhe (nstringhe). Quando si ha la corrispondenza, la funzione non fa altro che restituire la corrispondente stringa tradotta tradstr.
Si possono avere 2 casi: variabile nstringhe=0, ovvero la procedura 'genitrice' non ha trovato alcun file di linguaggio e quindi la funzione translate() non fa altro che restituire proprio la stringa che avrebbe dovuto tradurre (quindi non viene eseguito il ciclo for e non viene tradotto un bel nulla), oppure che si sia arrivati alla fine del ciclo for senza trovare alcuna corrispondenza (perchè quella specifica stringa non è presente nel file di linguaggio). Anche in questo caso la stringa restituita è proprio original e di fatto non si è tradotto nulla.
Con questo modo di procedere il programmatore deve stare attento a cosa digita via via che inserisce le righe di traduzione delle singole didascalie, ma almeno una stringa non tradotta verrà visualizzata nella lingua di default, piuttosto che con una stringa tipo: "Not traslated string", che renderebbe realmente incomprensibile all'utente straniero di cosa tratta quello specifico input.
A questo punto si deve intervenire nel codice in due casi:
1) Inserimento di una nuova finestra di dialogo, con sue specifiche stringhe da tradurre (ma se devo inserire una nuova finestra, sto di già intervenendo nel codice); 2) Inserimento di una nuova lingua (ovvero devo inserire una sola riga con il nome del file da aprire per quello specifico linguaggio).
Ovviamente per aggiungere una nuova lingua bisognerà scrivere il file di testo di cui all'inizio. E sempre ovviamente l'aggiunta di una nuova finestra e nuove didascalie comporta un ampliamento del/dei file di linguaggio.
|
|