Italian Applicazione multilingua

AlpVir

Well-Known Member
Licensed User
Longtime User
Vorrei trasformare una mia applicazione in multilingua. in modo da raggiungere un maggior numero di utenti.
Supponendo per semplicità di avere un pulsante "APRI" e che la lingua sia memorizzata nella variabile globale Lingua, ho pensato un primo metodo :
B4X:
Select case Lingua
   Case "ITA" : BotApri.text = "APRI"
   Case "ENG" : BotApri.text = "OPEN"
   Case "FRA" : BotApri.text = "OUVRIR"
End Select
che però ho scartato perchè macchinoso e soprattutto perchè aggiungere una nuova lingua sarebbe assai laborioso.

Il secondo metodo da me pensato prevede l'uso di alcuni file di testo (forse ti tipo XML) del tipo
"NomeApp_ITA.XML"
"NomeApp_ENG.XML"
"NomeApp_FRA.XML"
ciascuno per una specifica lingua.

In Activity_Create scriverei semplicemente
B4X:
 BotApri.text = Traduci("APRI")
che è abbastanza semplice da scrivere. Differisce poco dal
B4X:
BotApri.text = "APRI"
consueto.
Segue qui la bozza della sub Traduci.

B4X:
Sub Traduci(Testo as string)
  Dim Traduzione as string 
  Dim Trovato as boolean
  if Lingua="ITA" then
    Return Testo     ' non bisogna proseguire, l'italiano è predefinito
  end if
  FileXML = NomeApp & "_XML.XML"
  Trovato=False    
  ' a questo punto leggo lo specifico file XML fino a trovare la prima 
  ' occorrenza di "APRI" e la sua relativa traduzione nella specifica lingua
  ' .................
  . .................
  If Trovato=True then 
     Return Traduzione
  else
    Return Testo     ' non traduco, accetto il testo in italiano
  end if
End Sub

Ed ecco come sarebbe scritto, secondo questa ipotesi, un file XML; in questo caso per l'inglese. Premetto che non conosco quasi questo tipo di file.
B4X:
<XML>
  <ITEM>
    <ORIGINALE>APRI</ORIGINALE>
    <TRADUZIONE>OPEN</TRADUZIONE>
  </ITEM>
 <ITEM>
    <ORIGINALE>CHIUDI</ORIGINALE>
    <TRADUZIONE>CLOSE</TRADUZIONE>
  </ITEM>
</XML>


La domanda è: ho reinventato l'acqua calda ?
Vale la pena di utilizzare i file XML o un semplice file di testo potrebbe sostituirlo ? Ma forse con i file XML ci sono maggiori possibilità di interazione, di facile e veloce ricerca.
Ci sono soluzioni alternative migliori ?
Esistono dei tool che, dandogli in pasto un file .BAS, creano automaticamente il file XML con tutti i testi pronto per essere sottoposto - manualmente - all'operazione di traduzione/adattamento ?
Soprattutto: come rendere efficiente la ricerca (nell'esempio) di "APRI" e la sua traduzione "OPEN" ?
Grazie per l'attenzione.

P.S.: Se, con un po' di lavoro in più, si dispongono in ordine alfabetico i vari item nei file di traduzione, allora si può fare una più veloce ricerca binaria invece che quella sequenziale, tipica del ciclo FOR NEXT.
 
Last edited:

timo

Active Member
Licensed User
Longtime User
Io avevo risolto per un'app trilingue mettendo tre radioButtons in homepage. L'app riapriva ricordando l'ultima lingua scelta. Le altre activities facevano riferimento a main.vLingua:
B4X:
Sub Process_Globals
   Dim vLingua As Int   : vLingua = 3 '(default)/1=F 2=D 3=I  
End Sub

Sub Activity_Resume
'leggi e carica la lingua usata per ultima
If File.Exists(File.DirInternal,"lingua.txt") Then
   vLingua=(File.ReadString(File.DirInternal,"lingua.txt"))
   optLingua
End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
'salva la lingua e la legge in resume
File.WriteString(File.DirInternal, "lingua.txt", vLingua)
End Sub
Sub Activity_Create(FirstTime As Boolean)
optLingua
End Sub

Sub optLingua()
If vLingua=1 Then
radFR.Checked=True
radDE.Checked=False
radIT.Checked=False
End If
If vLingua=2 Then
radFR.Checked=False
radDE.Checked=True
radIT.Checked=False
End If
If vLingua=3 Then
radFR.Checked=False
radDE.Checked=False
radIT.Checked=True
End If
If vLingua=1 Then imgSfondo.Bitmap=LoadBitmap(File.DirAssets, "logo.png")
If vLingua=2 Then imgSfondo.Bitmap=LoadBitmap(File.DirAssets, "logoD.png")
If vLingua=3 Then imgSfondo.Bitmap=LoadBitmap(File.DirAssets, "logo.png")
If vLingua= 1 Then btnAdd.Text="Nouveau"
If vLingua= 2 Then btnAdd.Text="Neu"
If vLingua= 3 Then btnAdd.Text="Nuovo"

If vLingua=1 Then
lblCognome.Text="Nom"
lblNome.Text="Prénom"
lblMeseNascita.Text="mois de naiss."
lblAnnoNascita.Text="année de naiss."      
radU.Text="H"
radF.Text="F"
End If

If vLingua=2 Then
lblCognome.Text="Name"
lblNome.Text="Vorname"
lblMeseNascita.Text="geb.Monat"
lblAnnoNascita.Text="geb.Jahr"      
radU.Text="H"
radF.Text="F"
End If

If vLingua=3 Then
lblCognome.Text="Cognome"
lblNome.Text="Nome"
lblMeseNascita.Text="mese di nascita"
lblAnnoNascita.Text="anno di nascita"      
radU.Text="U"
radF.Text="D"
End If
'...ecc.
End Sub

Sub radFR_CheckedChange(Checked As Boolean)
   If radFR.Checked=True Then 
   vLingua=1
   optLingua
   End If
End Sub
Sub radDE_CheckedChange(Checked As Boolean)
   If radDE.Checked=True Then 
   vLingua=2
   optLingua
   End If
End Sub
Sub radIT_CheckedChange(Checked As Boolean)
   If radIT.Checked=True Then
   vLingua=3
   optLingua
   End If
End Sub
 

Attachments

  • lingua.jpg
    lingua.jpg
    5.2 KB · Views: 255

AlpVir

Well-Known Member
Licensed User
Longtime User
La soluzione di Timo è sostanzialmente simile alla prima da me proposta e scartata perchè è inglobata all'interno delll'applicazione (difficile da mantenere).
La seconda era da me già conosciuta ma scartata in un primo momento perchè mi pareva rivolta più che altro alla modifica di certi parametri (valuta, date, ecc.).
Mi accorgo ora che c'è anche la posssibilità di "traduzioni".
B4X:
btParameter.Text = trans.GetText("Translation with variable values")
Se non trovo un sistema (meno risorse consumate e più veloce) migliore adotterò questo.
Resta l'idea (interessante a mio parere) di un programma per Windows che faccia automaticamente tutto il lavoro più tedioso.
Grazie ad entrambi.
 

moster67

Expert
Licensed User
Longtime User
Secondo me la libreria AHLocale (come suggerito da Filippo) è la strada giusta.

Il modo ufficale sarebbe da usare "Android-Localisation". Vedi questo thread:

http://www.b4x.com/forum/basic4android-updates-questions/15172-standard-android-localisation-feature-possible.html#post86103

Ma sembra che in questo momento non è possibile usare questo methodo al 100% in B4A.

Ho trovato anche questo code-module qui nel forum:

http://www.b4x.com/forum/basic4android-getting-started-tutorials/10543-activity-translation.html#post58672
 

AlpVir

Well-Known Member
Licensed User
Longtime User
Alla fine ho scelto una soluzione intermedia che, a mio giudizio, prende il meglio da ciascuna. Forse ho inventato l'acqua tiepida ;-)
Il nucleo centrale è la sub Traduci in cui la variabile Lingua è globale.
B4X:
Sub Traduci (Testo As String) 
   Dim i          As Int 
   Dim Trovato    As Boolean 
   Dim Traduzione As String 
   '
   If Lingua="ITA" Then Return Testo
   For i = 0 To Map1.Size - 1
      If MapLingua.GetKeyAt(i)=Testo Then
         Traduzione=MapLingua.GetValueAt(i)
         Trovato=True
         Exit 
         End If      
   Next
    If Trovato=False Then Traduzione=Testo
   Return Traduzione
End Sub

richiamata in questo modo

B4X:
BotAiuto.Text = Traduci("AIUTO")


I file con le traduzioni sono richiamati in Activity_Resume
B4X:
FileTraduzioni=CartellaDataBase & "/360ALP_" & Lingua & ".txt"
   If File.Exists(File.DirRootExternal, FileTraduzioni) Then  
      MapLingua.Initialize 
      MapLingua = File.ReadMap(File.DirRootExternal,FileTraduzioni)
   Else
      Lingua="ITA"
   End If
Ed ecco un semplice file di traduzioni, tutto da controllare
B4X:
TOPONIMI=TOPOS
ARCHIVI=ARCHIVE
SINTETICO=SYNTETIC
AIUTO=HELP
VEDI=VIEW
Cerca nome=Find name
Autore=Author
Data=Date

Resta da vedere come il sistema reagisce quando gli item presenti nei file di traduzione diventano numerosi. Speriamo !

Buona Pasqua a tutti

P.S: Se, con un po' di lavoro in più, si dispongono in ordine alfabetico i vari item nei file di traduzione, allora si può fare una veloce ricerca binaria in luogo di quella sequanziale, tipica dei cicli FOR NEXT. E' da sperimentare !
 
Last edited:

Jost aus Soest

Active Member
Licensed User
Longtime User
B4X:
For i = 0 To Map1.Size - 1
  If MapLingua.GetKeyAt(i)=Testo Then
    Traduzione=MapLingua.GetValueAt(i)
    Trovato=True
    Exit 
   End If      
Next

Come mai non provi di evitare il For-Next ed usare l'accesso diretto, per esempio:
B4X:
Traduzione = MapLingua.Get(Testo)
 

timo

Active Member
Licensed User
Longtime User
Guarda, ne avevo provate di tutti i colori e ho notato che in alcune situazioni la risorsa esterna poteva dare problemi (msgbox e affini in particolare). Alla fine la soluzione più sicura e veloce si è dimostrata proprio quella interna. Il programma è molto grande (non solo per le lingue), ma essendo destinato ad una cerchia precisa di utilizzatori, ho preferito la sicurezza totale. Funziona bene e non ci sono stati mai inconvenienti (facendo le corna :)).
Calcola che le Activity non caricate non disturbano, quindi-avendo il tutto spezzettato- alla fine la velocità rimane praticamente identica al monolingua.
Non ho mai riscontrato un comportamento in Activity.Finish come segnalato da qualche parte (Android che rifiuta di eseguire subito), quindi neppure un intasamento della ram. La progettazione del tutto è quindi fondamentale.

Il mio utilizzatore tipo usa una sola lingua (su poche), impostata la prima volta. Chiaramente se devi basarti sulla localizzazione geografica ,in distribuzione da market, la storia cambia, E l'affidbilità pure.

Te lo segnalo come esperienza pratica fatta. Ma tutto dipende da tanti fattori ed una soluzione può essere buona in un caso e pessima in un altro.
 

AlpVir

Well-Known Member
Licensed User
Longtime User
Perchè non ho usato l'accesso diretto ?
Perchè non lo sapevo. Grazie dell'informazione.
La sub è quindi diventata
B4X:
Sub Traduci (Testo As String) 
   Dim Traduzione As String 
   '
   If Lingua="ITA" Then Return Testo
   Traduzione = MapLingua.Get(Testo)
   Return Traduzione.Replace("_"," ")
End Sub
Se "Testo" comprende degli spazi bisogna scrivere, nel file di traduzioni,
"due_parole" per vedersi restituire "two word".
Quanto alle prestazioni del metodo utilizzato per adesso mi sembra tutto OK.
Come dice Timo bisogna adattarsi ed adottare varie soluzioni. Vedi ad esempio il misterioso fatto che l'istruzione
B4X:
ProgressDialogShow (Traduci("Attendere"))
non funziona. Poco male.
Grazie ancora.
 
Last edited:

AlpVir

Well-Known Member
Licensed User
Longtime User
Il funzionamento apparentemente è identico. La tua proposta (accettata) nasce da un desiderio di chiarezza del codice o che altro ?
Altra piccola modifica :
B4X:
If Main.Lingua="ITA" Then Return Testo.Replace("_"," ")
 
Top