Android Question Multilanguage

luke2012

Well-Known Member
Licensed User
Longtime User
Hi to all and good holidays! :)
which is the best solution to implement multilanguage in a B4A apps?
 

sorex

Expert
Licensed User
Longtime User
I think there was a library to add localization support.

you could also just put your text field values in a text/json/xml file (or sqlite table) and add the different language values there.
Read them out based on the selected language value and store it into the labels.
 
Upvote 0

nwhitfield

Active Member
Licensed User
Longtime User
There are lots of different ways; the approach I've taken for one of my apps is a weird hybrid one that allows adding extra languages to an app at any time, without users having to re-download it.

The basics is to have a text file in the format supported by File.ReadMap containing all the strings for the language. I have all this in a code module called BLUFtools, which itself shares a BLUFstrings Map with the rest of the app and also a Months map. The file looks something like this

B4X:
# so the code knows which language it is using at the moment
language = en
# this is a comment
# buttons for my UI
B_ok = OK
B_back = Back
B_more = More

For languages that are included with the app, I add the file to the project's Files tab in B4A. Note that here, you need to have the file in a Windows char set - mine are all in Latin 1; but for delivering from a server, you need to use UTF8. Don't ask me why.

So, built-in languages are in the DirAssets, while downloaded ones are put in DefaultInternal. All are named as lang-<code>.txt, for instance lang-en.txt, lang-de.txt, lang-fr.txt

My code module also contains a sub, getDeviceLanguage, which uses Reflection to see what the device is set to, and the prefs page allows people to set their preferred choice, as a two letter string. That's stored with StateManager. So, when the app launches, it gets to this code:

B4X:
  ' set up the language ; english is default
   If BLUFtools.initLanguage(StateManager.GetSetting2("language",BLUFtools.getDeviceLanguage)) = False Then
     BLUFtools.initLanguage("en")
   End If

In other words, if there's a preference set, it will try to load that language, otherwise it will try to load the device language, and if that fails (no language file) then it falls back to English.

The initLanguage sub looks like this:

B4X:
Sub initLanguage( language As String) As Boolean
   ' initialise the requested language
   If BLUFstrings.IsInitialized = False Then
     BLUFstrings.Initialize
   End If
  
   If BLUFstrings.ContainsKey("language") AND BLUFstrings.get("language") = language Then
     Log("Language: set to " & BLUFstrings.Get("language"))
     Return True
   Else
     ' we need to load the strings for the requested language
     ' we do this from a file in the assets folder
     ' with the name lang-<language>.txt
     If File.Exists(File.DirAssets,"lang-" & language & ".txt") OR File.Exists(File.DirInternal,"lang-" & language & ".txt") Then
       ' use the built in strings
       If File.Exists(File.DirAssets,"lang-" & language & ".txt") Then
         Log("Language: reading built in file for " & language)
         BLUFstrings = File.ReadMap(File.DirAssets,"lang-" & language & ".txt")
       Else
         ' downloaded version
         Log("Language: reading downloaded file for " & language)
         BLUFstrings = File.ReadMap(File.DirInternal,"lang-" & language & ".txt")
       End If
      
       ' process the months of the year
       months.Clear
       months.AddAll(Array As String( BLUFstrings.get("D_jan"),BLUFstrings.get("D_feb"),BLUFstrings.get("D_mar"),BLUFstrings.get("D_apr"),BLUFstrings.get("D_may"),BLUFstrings.get("D_jun"),BLUFstrings.get("D_jul"),BLUFstrings.get("D_aug"),BLUFstrings.get("D_sep"),BLUFstrings.get("D_oct"),BLUFstrings.get("D_nov"),BLUFstrings.get("D_dec")))
      
       Return True
     Else
       Log("Language: unable to load " & language)
       Return False
     End If
   End If
End Sub

Once this is done, I can set up my UI by saying things like

B4X:
dim labelOK as label
labelOK.initialize("OK")
labelOK.text = BLUFtools.BLUFstrings.get("B_ok")

My prefs activity has a sub that asks the server for a list of languages, which is returned as a JSON array, indicating which languages there are files for on the server, their names (in that language) and the two character code.

The app then checks to see which of those is has in the Assets and Internal folders, and makes a menu showing all the options, plus 'Use device language' - items for which there is a file present are marked as 'Installed' in the menu. If the user chooses one of those, it can be used immediately with the initLanguage option; if not, then it's requested from the server, which returns it as JSON. That can be easily put into a map, then saved using File.WriteMap, and loaded like the other languages.

For us, this is handy, as it means that if one of our users wants to contribute, for example, an Italian translation, it can be made available to everyone who wants it, without all users being bothered by an update that won't change anything for them.

One thing to note, of course, is that if you do it like this, text that is on screen won't be updated until you make that happen. So, in the main app, we reload the texts on activity resume; an alternative is to tell people to restart the app after changing language.

This is by no means the only way to solve the problem, but it might be useful to some of you.
 
Upvote 0

Similar Threads

  • Article
Share My Creation ToDo list
Replies
13
Views
6K
Replies
64
Views
25K
Replies
16
Views
12K
Top