Tool A holistic approach to internationalization for B4(A/J) application (Intro)

I have developed a tool to help code and maintain multilingual B4A and B4J applications with ease.

It’s a Windows application written in C#: B4Multilingual and a B4(A/J) helper library.

The tool is in beta and I need a few people who would be happy to test run it before I release it to the community.

You'll need:
  • .NET 4.5 installed (as most of you, Windows users, will have if you're using the the latest B4A executable).
  • A Microsoft Bing Translator free account.
  • Some fortitude as the doc will be added to this post gradually.
How it works in a nutshell:
  1. You enter all the texts that will be required in your application in your chosen language.
  2. You choose all the languages you want the different texts to be translated into.
  3. You click a button. The app connects to Microsoft Bing Translator web service and populates the SQLite database with the relevant translations.
  4. Finally, if you wish, you can generate the code to use in B4(A/J) application.
Here are a few screenshots:

Applications Form:
You can maintain multiple applications. You can do all CRUD operations.
4h8c5s.jpg


Keys Form:
Keys
are unique IDs used by the application to generate translations and B4 code. The Default Text is the text in your default language, and will be used whenever there's no translation available.

In conformance with Google's conventions, there are 3 types of keys: Single, Plurals, Arrays. Single represents a simple string, such as Settings in the grid below. Plurals are translations for plurals of the same word (car, cars) and finally Arrays are lists of strings, example Planets_ (Mercury, Venus etc.)
34dkiet.jpg


Locales Form:
Select the languages you want translations for. Selected locales are highlighted in red. Not all languages will be available, but Microsoft keeps adding new ones. About 50 are currently available.
21cgtar.jpg


Translations Form:
All the texts are translated for the selected application (Bouncer). You can delete all the ones which are not required and make sure that the translations are correct! Edit them if necessary.
2zfsupv.jpg


Code Generation Settings:
You may choose to generate the B4 code to add to your application. You can either generate a pure B4(A/J) class or a set of XML files (according to Google's standards) with B4 code. A few settings are available as of now. More will be added.
16k0tiq.jpg


Here's the generated code when Class is checked.
B4X:
'B4Multingual B4A/B4J Generated Code
Private Sub Class_Globals
   Private translationMap As Map
   Private oAJLocale As AJLocale
   Private oAJDateFormatSymbols As AJDateFormatSymbols
   Private oAJCalendar As AJCalendar
   Private oAJCurrency As AJCurrency
   Private default_language_translation_ As String
   '
#Region varSYMBOLS
   Private const author_ As Int = 0
   Private const automated_ As Int = 1
   Private const both_ As Int = 2
   Private const card_range_ As Int = 3
   Private const clubs_ As Int = 4
   Private const currency_ As Int = 5
   Private const currency_symbol_ As Int = 6
   Private const current_language_ As Int = 7
   Private const delete_ As Int = 8
   Private const description_ As Int = 9
   Private const diamonds_ As Int = 10
   Private const export_stack_ As Int = 11
   Private const first_week_day_ As Int = 12
   Private const hearts_ As Int = 13
   Private const help_ As Int = 14
   Private const home_ As Int = 15
   Private const import_ As Int = 16
   Private const import_stack_ As Int = 17
   Private const language_setting_ As Int = 18
   Private const manual_ As Int = 19
   Private const memdeck_ As Int = 20
   Private const name_ As Int = 21
   Private const order_ As Int = 22
   Private const planets_ As Int = 23
   Private const play_ As Int = 24
   Private const position_ As Int = 25
   Private const random_ As Int = 26
   Private const reversed_ As Int = 27
   Private const save_ As Int = 28
   Private const select_lang_ As Int = 29
   Private const select_month_ As Int = 30
   Private const select_weekday_ As Int = 31
   Private const sequential_ As Int = 32
   Private const settings_ As Int = 33
   Private const show_full_name_ As Int = 34
   Private const show_hint_ As Int = 35
   Private const show_index_ As Int = 36
   Private const show_picture_ As Int = 37
   Private const show_stack_no_ As Int = 38
   Private const spades_ As Int = 39
   Private const stacks_ As Int = 40
   Private const stack_maintenance_ As Int = 41
   Private const suits_ As Int = 42
   Private const test_ As Int = 43
   Private const text_to_speech_ As Int = 44
   Private const timer_ As Int = 45
   Private const title_ As Int = 46
   Private const trans_with_var_values_ As Int = 47
   Private const variable_message_ As Int = 48
   Private const car_ As Int = 49
   Private const cards_ As Int = 50
   Private const planets__ As Int = 51
#End Region varSYMBOLS

#Region varLOCALES
   Private const EN As String = "en" 'English:Default Language
   Private const FR As String = "fr" 'French
   Private const IT As String = "it" 'Italian
#End Region varLOCALES
End Sub

#Region Initialize Methods
Private Sub InternalInitialize
   Dim r As Reflector
   r.Target = Me
   r.Runmethod4("innerInitialize", Array As Object(r.GetProcessBA("main")), Array As String("anywheresoftware.b4a.BA"))
End Sub

Public Sub Initialize
   PopulateTranslate
   oAJLocale.InitializeDefault
   SetHelperClasses(oAJLocale.Locale)

   default_language_translation_ = EN
End Sub

Public Sub Initialize2(default_language_translation As String)
   InternalInitialize
   '
   PopulateTranslate
   oAJLocale.Initialize(default_language_translation)
   SetHelperClasses(oAJLocale.Locale)

   default_language_translation_ = default_language_translation
End Sub

Private Sub SetHelperClasses(Locale As JavaObject)
   oAJDateFormatSymbols.Initialize2(Locale)
   oAJCalendar.GetInstance2(Locale)
   oAJDateFormatSymbols.Initialize2(Locale)
   Try
     oAJCurrency.GetInstance(Locale)
   Catch
     Log(LastException)
   End Try
End Sub
#End Region Initialize Methods

#Region LOCALES
Public Sub getEnglish As String
   Return EN
End Sub
Public Sub getFrench As String
   Return FR
End Sub
Public Sub getItalian As String
   Return IT
End Sub
#End Region LOCALES

#Region KEYS
Public Sub getauthor As String
   Return Get_(author_)
End Sub
Public Sub getautomated As String
   Return Get_(automated_)
End Sub
Public Sub getboth As String
   Return Get_(both_)
End Sub
Public Sub getcard_range As String
   Return Get_(card_range_)
End Sub
Public Sub getclubs As String
   Return Get_(clubs_)
End Sub
Public Sub getcurrency As String
   Return Get_(currency_)
End Sub
Public Sub getcurrency_symbol As String
   Return Get_(currency_symbol_)
End Sub
Public Sub getcurrent_language As String
   Return Get_(current_language_)
End Sub
Public Sub getdelete As String
   Return Get_(delete_)
End Sub
Public Sub getdescription As String
   Return Get_(description_)
End Sub
Public Sub getdiamonds As String
   Return Get_(diamonds_)
End Sub
Public Sub getexport_stack As String
   Return Get_(export_stack_)
End Sub
Public Sub getfirst_week_day As String
   Return Get_(first_week_day_)
End Sub
Public Sub gethearts As String
   Return Get_(hearts_)
End Sub
Public Sub gethelp As String
   Return Get_(help_)
End Sub
Public Sub gethome As String
   Return Get_(home_)
End Sub
Public Sub getimport As String
   Return Get_(import_)
End Sub
Public Sub getimport_stack As String
   Return Get_(import_stack_)
End Sub
Public Sub getlanguage_setting As String
   Return Get_(language_setting_)
End Sub
Public Sub getmanual As String
   Return Get_(manual_)
End Sub
Public Sub getmemdeck As String
   Return Get_(memdeck_)
End Sub
Public Sub getname As String
   Return Get_(name_)
End Sub
Public Sub getorder As String
   Return Get_(order_)
End Sub
Public Sub getplanets As String
   Return Get_(planets_)
End Sub
Public Sub getplay As String
   Return Get_(play_)
End Sub
Public Sub getposition As String
   Return Get_(position_)
End Sub
Public Sub getrandom As String
   Return Get_(random_)
End Sub
Public Sub getreversed As String
   Return Get_(reversed_)
End Sub
Public Sub getsave As String
   Return Get_(save_)
End Sub
Public Sub getselect_lang As String
   Return Get_(select_lang_)
End Sub
Public Sub getselect_month As String
   Return Get_(select_month_)
End Sub
Public Sub getselect_weekday As String
   Return Get_(select_weekday_)
End Sub
Public Sub getsequential As String
   Return Get_(sequential_)
End Sub
Public Sub getsettings As String
   Return Get_(settings_)
End Sub
Public Sub getshow_full_name As String
   Return Get_(show_full_name_)
End Sub
Public Sub getshow_hint As String
   Return Get_(show_hint_)
End Sub
Public Sub getshow_index As String
   Return Get_(show_index_)
End Sub
Public Sub getshow_picture As String
   Return Get_(show_picture_)
End Sub
Public Sub getshow_stack_no As String
   Return Get_(show_stack_no_)
End Sub
Public Sub getspades As String
   Return Get_(spades_)
End Sub
Public Sub getstacks As String
   Return Get_(stacks_)
End Sub
Public Sub getstack_maintenance As String
   Return Get_(stack_maintenance_)
End Sub
Public Sub getsuits As String
   Return Get_(suits_)
End Sub
Public Sub gettest As String
   Return Get_(test_)
End Sub
Public Sub gettext_to_speech As String
   Return Get_(text_to_speech_)
End Sub
Public Sub gettimer As String
   Return Get_(timer_)
End Sub
Public Sub gettitle As String
   Return Get_(title_)
End Sub
Public Sub gettrans_with_var_values As String
   Return Get_(trans_with_var_values_)
End Sub
Public Sub getvariable_message As String
   Return Get_(variable_message_)
End Sub
Public Sub getcarMap As Map
   Return GetMap_(car_)
End Sub
Public Sub getcardsMap As Map
   Return GetMap_(cards_)
End Sub
Public Sub getplanets_Map As Map
   Return GetMap_(planets__)
End Sub
#End Region KEYS

#Region Public Methods
Public Sub getAJLocale As AJLocale
   Return oAJLocale
End Sub

Public Sub setAJLocale(AJLocale As AJLocale)
   oAJLocale = AJLocale
   SetHelperClasses(oAJLocale.Locale)
End Sub

Public Sub getAJDateFormatSymbols As AJDateFormatSymbols
   Return oAJDateFormatSymbols
End Sub

Public Sub getAJCalendar As AJCalendar
   Return oAJCalendar
End Sub

Public Sub getAJCurrency As AJCurrency
   Return oAJCurrency
End Sub

Public Sub setAJCurrency(AJCurrency As AJCurrency)
   oAJCurrency = AJCurrency
End Sub

Private Sub Get_(symbol As Int) As String
   Return Get(symbol, oAJLocale.GetLanguage)
End Sub

Public Sub Get(symbol As Int, lang As String) As String
   Dim line_map As Map
   line_map = translationMap.Get(symbol)
   Return(line_map.GetDefault(lang, line_map.Get(default_language_translation_)))
End Sub

Private Sub GetMap_(symbol As Int) As Map
   Return GetMap(symbol, oAJLocale.GetLanguage)
End Sub

Public Sub GetMap(symbol As Int, lang As String) As Map
   Dim lines_map As Map
   lines_map = translationMap.Get(symbol)
   Return lines_map.GetDefault(lang, lines_map.Get(default_language_translation_))
End Sub
#End Region Public Methods

Private Sub PopulateTranslate
   Dim line_map As Map
   Dim lines_map As Map
   translationMap.Initialize

   '0: AUTHOR
   line_map.Initialize
   line_map.Put(EN,"Author")
   line_map.Put(FR,"Auteur")
   line_map.Put(IT,"Autore")
   translationMap.Put(author_, line_map)

   '1: AUTOMATED
   line_map.Initialize
   line_map.Put(EN,"Automated")
   line_map.Put(FR,"Automatisé")
   line_map.Put(IT,"Automatizzato")
   translationMap.Put(automated_, line_map)

   '2: BOTH
   line_map.Initialize
   line_map.Put(EN,"Both")
   line_map.Put(FR,"Tous les deux")
   line_map.Put(IT,"Entrambi")
   translationMap.Put(both_, line_map)

   '3: CARD_RANGE
   line_map.Initialize
   line_map.Put(EN,"Card Range")
   line_map.Put(FR,"Carte de gamme")
   line_map.Put(IT,"Gamma di carta")
   translationMap.Put(card_range_, line_map)

   '4: CLUBS
   line_map.Initialize
   line_map.Put(EN,"Clubs")
   line_map.Put(FR,"Clubs")
   line_map.Put(IT,"Club")
   translationMap.Put(clubs_, line_map)

   '5: CURRENCY
   line_map.Initialize
   line_map.Put(EN,"Currency")
   line_map.Put(FR,"Devise")
   line_map.Put(IT,"Valuta")
   translationMap.Put(currency_, line_map)

   '6: CURRENCY_SYMBOL
   line_map.Initialize
   line_map.Put(EN,"Currency Symbol")
   line_map.Put(FR,"Symbole monétaire")
   line_map.Put(IT,"Simbolo di valuta")
   translationMap.Put(currency_symbol_, line_map)

   '7: CURRENT_LANGUAGE
   line_map.Initialize
   line_map.Put(EN,"Current Language")
   line_map.Put(FR,"Langage courant")
   line_map.Put(IT,"Lingua corrente")
   translationMap.Put(current_language_, line_map)

   '8: DELETE
   line_map.Initialize
   line_map.Put(EN,"Delete")
   line_map.Put(FR,"Supprimer")
   line_map.Put(IT,"Elimina")
   translationMap.Put(delete_, line_map)

   '9: DESCRIPTION
   line_map.Initialize
   line_map.Put(EN,"Description")
   line_map.Put(FR,"Description")
   line_map.Put(IT,"Descrizione")
   translationMap.Put(description_, line_map)

   '10: DIAMONDS
   line_map.Initialize
   line_map.Put(EN,"Diamonds")
   line_map.Put(FR,"Diamants")
   line_map.Put(IT,"Diamanti")
   translationMap.Put(diamonds_, line_map)

   '11: EXPORT_STACK
   line_map.Initialize
   line_map.Put(EN,"Export Stack")
   line_map.Put(FR,"Pile d'exportation")
   line_map.Put(IT,"Stack di esportazione")
   translationMap.Put(export_stack_, line_map)

   '12: FIRST_WEEK_DAY
   line_map.Initialize
   line_map.Put(EN,"First day of week")
   line_map.Put(FR,"Premier jour de la semaine")
   line_map.Put(IT,"Primo giorno della settimana")
   translationMap.Put(first_week_day_, line_map)

   '13: HEARTS
   line_map.Initialize
   line_map.Put(EN,"Hearts")
   line_map.Put(FR,"Coeurs")
   line_map.Put(IT,"Cuori")
   translationMap.Put(hearts_, line_map)

   '14: HELP
   line_map.Initialize
   line_map.Put(EN,"Help")
   line_map.Put(FR,"Aide")
   line_map.Put(IT,"Guida")
   translationMap.Put(help_, line_map)

   '15: HOME
   line_map.Initialize
   line_map.Put(EN,"Home")
   line_map.Put(FR,"Accueil")
   line_map.Put(IT,"Casa")
   translationMap.Put(home_, line_map)

   '16: IMPORT
   line_map.Initialize
   line_map.Put(EN,"Import")
   line_map.Put(FR,"Importation")
   line_map.Put(IT,"Importazione")
   translationMap.Put(import_, line_map)

   '17: IMPORT_STACK
   line_map.Initialize
   line_map.Put(EN,"Import Stack")
   line_map.Put(FR,"Pile d'importation")
   line_map.Put(IT,"Stack di importazione")
   translationMap.Put(import_stack_, line_map)

   '18: LANGUAGE_SETTING
   line_map.Initialize
   line_map.Put(EN,"Language Setting")
   line_map.Put(FR,"Paramètre de langue")
   line_map.Put(IT,"Impostazione della lingua")
   translationMap.Put(language_setting_, line_map)

   '19: MANUAL
   line_map.Initialize
   line_map.Put(EN,"Manual")
   line_map.Put(FR,"Manuelle")
   line_map.Put(IT,"Manuale")
   translationMap.Put(manual_, line_map)

   '20: MEMDECK
   line_map.Initialize
   line_map.Put(EN,"Memorized deck")
   line_map.Put(FR,"Pont mémorisée")
   line_map.Put(IT,"Ponte memorizzato")
   translationMap.Put(memdeck_, line_map)

   '21: NAME
   line_map.Initialize
   line_map.Put(EN,"Name")
   line_map.Put(FR,"Nom")
   line_map.Put(IT,"Nome")
   translationMap.Put(name_, line_map)

   '22: ORDER
   line_map.Initialize
   line_map.Put(EN,"Order")
   line_map.Put(FR,"Ordonnance")
   line_map.Put(IT,"Ordine")
   translationMap.Put(order_, line_map)

   '23: PLANETS
   line_map.Initialize
   line_map.Put(EN,"Planets")
   line_map.Put(FR,"Planètes")
   line_map.Put(IT,"Pianeti")
   translationMap.Put(planets_, line_map)

   '24: PLAY
   line_map.Initialize
   line_map.Put(EN,"Play")
   line_map.Put(FR,"Jouer")
   line_map.Put(IT,"Gioca")
   translationMap.Put(play_, line_map)

   '25: POSITION
   line_map.Initialize
   line_map.Put(EN,"Position")
   line_map.Put(FR,"Position")
   line_map.Put(IT,"Posizione")
   translationMap.Put(position_, line_map)

   '26: RANDOM
   line_map.Initialize
   line_map.Put(EN,"Random")
   line_map.Put(FR,"Au hasard")
   line_map.Put(IT,"Casuale")
   translationMap.Put(random_, line_map)

   '27: REVERSED
   line_map.Initialize
   line_map.Put(EN,"Reversed")
   line_map.Put(FR,"Inversé")
   line_map.Put(IT,"Invertito")
   translationMap.Put(reversed_, line_map)

   '28: SAVE
   line_map.Initialize
   line_map.Put(EN,"Save")
   line_map.Put(FR,"Enregistrer")
   line_map.Put(IT,"Salva")
   translationMap.Put(save_, line_map)

   '29: SELECT_LANG
   line_map.Initialize
   line_map.Put(EN,"Select Language")
   line_map.Put(FR,"Sélectionner une langue")
   line_map.Put(IT,"Seleziona lingua")
   translationMap.Put(select_lang_, line_map)

   '30: SELECT_MONTH
   line_map.Initialize
   line_map.Put(EN,"Select Month")
   line_map.Put(FR,"Sélectionnez le mois")
   line_map.Put(IT,"Selezionare il mese")
   translationMap.Put(select_month_, line_map)

   '31: SELECT_WEEKDAY
   line_map.Initialize
   line_map.Put(EN,"Select Weekday")
   line_map.Put(FR,"Sélectionnez le jour de la semaine")
   line_map.Put(IT,"Selezionare il giorno della settimana")
   translationMap.Put(select_weekday_, line_map)

   '32: SEQUENTIAL
   line_map.Initialize
   line_map.Put(EN,"Sequential")
   line_map.Put(FR,"Séquentiel")
   line_map.Put(IT,"Sequenziale")
   translationMap.Put(sequential_, line_map)

   '33: SETTINGS
   line_map.Initialize
   line_map.Put(EN,"Settings")
   line_map.Put(FR,"Paramètres")
   line_map.Put(IT,"Impostazioni")
   translationMap.Put(settings_, line_map)

   '34: SHOW_FULL_NAME
   line_map.Initialize
   line_map.Put(EN,"Show Full Name")
   line_map.Put(FR,"Afficher le nom complet")
   line_map.Put(IT,"Visualizza nome e cognome")
   translationMap.Put(show_full_name_, line_map)

   '35: SHOW_HINT
   line_map.Initialize
   line_map.Put(EN,"Show Hint")
   line_map.Put(FR,"Afficher l'indice")
   line_map.Put(IT,"Mostra suggerimenti")
   translationMap.Put(show_hint_, line_map)

   '36: SHOW_INDEX
   line_map.Initialize
   line_map.Put(EN,"Show Index")
   line_map.Put(FR,"Show Index")
   line_map.Put(IT,"Visualizza indice")
   translationMap.Put(show_index_, line_map)

   '37: SHOW_PICTURE
   line_map.Initialize
   line_map.Put(EN,"Show Picture")
   line_map.Put(FR,"Voir la photo")
   line_map.Put(IT,"Visualizza foto")
   translationMap.Put(show_picture_, line_map)

   '38: SHOW_STACK_NO
   line_map.Initialize
   line_map.Put(EN,"Show Stack No")
   line_map.Put(FR,"Voir la pile non")
   line_map.Put(IT,"Visualizza Stack No")
   translationMap.Put(show_stack_no_, line_map)

   '39: SPADES
   line_map.Initialize
   line_map.Put(EN,"Spades")
   line_map.Put(FR,"Pique")
   line_map.Put(IT,"Picche")
   translationMap.Put(spades_, line_map)

   '40: STACKS
   line_map.Initialize
   line_map.Put(EN,"Stacks")
   line_map.Put(FR,"Piles")
   line_map.Put(IT,"Stack")
   translationMap.Put(stacks_, line_map)

   '41: STACK_MAINTENANCE
   line_map.Initialize
   line_map.Put(EN,"STACK MAINTENANCE")
   line_map.Put(FR,"ENTRETIEN DE LA PILE")
   line_map.Put(IT,"MANUTENZIONE DELLO STACK")
   translationMap.Put(stack_maintenance_, line_map)

   '42: SUITS
   line_map.Initialize
   line_map.Put(EN,"Suits")
   line_map.Put(FR,"Convient à")
   line_map.Put(IT,"Si adatta alle")
   translationMap.Put(suits_, line_map)

   '43: TEST
   line_map.Initialize
   line_map.Put(EN,"Test")
   line_map.Put(FR,"Test")
   line_map.Put(IT,"Prova")
   translationMap.Put(test_, line_map)

   '44: TEXT_TO_SPEECH
   line_map.Initialize
   line_map.Put(EN,"Text To Speech")
   line_map.Put(FR,"Text To Speech")
   line_map.Put(IT,"Text To Speech")
   translationMap.Put(text_to_speech_, line_map)

   '45: TIMER
   line_map.Initialize
   line_map.Put(EN,"Timer")
   line_map.Put(FR,"Heures")
   line_map.Put(IT,"Ore")
   translationMap.Put(timer_, line_map)

   '46: TITLE
   line_map.Initialize
   line_map.Put(EN,"Title")
   line_map.Put(FR,"Titre")
   line_map.Put(IT,"Titolo")
   translationMap.Put(title_, line_map)

   '47: TRANS_WITH_VAR_VALUES
   line_map.Initialize
   line_map.Put(EN,"Translation with variable values")
   line_map.Put(FR,"Traduction avec les valeurs des variables")
   line_map.Put(IT,"Traduzione con i valori delle variabili")
   translationMap.Put(trans_with_var_values_, line_map)

   '48: VARIABLE_MESSAGE
   line_map.Initialize
   line_map.Put(EN,"You are in %1$s and your Currency is %2$s")
   line_map.Put(FR,"Vous êtes à %1$s et votre monnaie est %2$s")
   line_map.Put(IT,"Sei in %1$s e la valuta è %2$s")
   translationMap.Put(variable_message_, line_map)

   '49: CARDS (string-srray)
   lines_map.Initialize
   line_map.Initialize
   line_map.Put(0, "Ace")
   line_map.Put(1, "King")
   line_map.Put(2, "Queen")
   line_map.Put(3, "Jack")
   lines_map.Put(EN, line_map)

   line_map.Initialize
   line_map.Put(0, "ACE")
   line_map.Put(1, "King")
   line_map.Put(2, "Reine")
   line_map.Put(3, "Jack")
   lines_map.Put(FR, line_map)

   line_map.Initialize
   line_map.Put(0, "Asso")
   line_map.Put(1, "Re")
   line_map.Put(2, "Regina")
   line_map.Put(3, "Jack")
   lines_map.Put(IT, line_map)
   translationMap.Put(cards_, lines_map)

   '50: PLANETS_ (string-srray)
   lines_map.Initialize
   line_map.Initialize
   line_map.Put(0, "Mercury")
   line_map.Put(1, "Venus")
   line_map.Put(2, "Earth")
   line_map.Put(3, "Mars")
   line_map.Put(4, "Jupiter")
   line_map.Put(5, "Saturn")
   line_map.Put(6, "Uranus")
   line_map.Put(7, "Neptune")
   lines_map.Put(EN, line_map)

   line_map.Initialize
   line_map.Put(0, "Mercure")
   line_map.Put(1, "Venus")
   line_map.Put(2, "Terre")
   line_map.Put(3, "Mars")
   line_map.Put(4, "Jupiter")
   line_map.Put(5, "Saturn")
   line_map.Put(6, "Uranus")
   line_map.Put(7, "Neptune")
   lines_map.Put(FR, line_map)

   line_map.Initialize
   line_map.Put(0, "Mercurio")
   line_map.Put(1, "Venus")
   line_map.Put(2, "Terra")
   line_map.Put(3, "Marzo")
   line_map.Put(4, "Giove")
   line_map.Put(5, "Saturno")
   line_map.Put(6, "Urano")
   line_map.Put(7, "Nettuno")
   lines_map.Put(IT, line_map)
   translationMap.Put(planets__, lines_map)

   '51: CAR (plurals-array)
   lines_map.Initialize
   line_map.Initialize
   line_map.Put("one", "car")
   line_map.Put("other", "cars")
   lines_map.Put(EN, line_map)

   line_map.Initialize
   line_map.Put("one", "voiture")
   line_map.Put("other", "voitures")
   lines_map.Put(FR, line_map)

   line_map.Initialize
   line_map.Put("one", "auto")
   line_map.Put("other", "Automobili")
   lines_map.Put(IT, line_map)
   translationMap.Put(car_, lines_map)
End Sub

Among other things, the great advantage of this approach is the way you assign texts to views etc. It's short and sweet:

Example:
B4X:
Dim oTr as Tr
oTr.Initialize

myLabel.Text = oTr.Author
myOtherView.Text = oTr.Settings

Obviously, the class will detect the current locale (language) and display the correct text.

Edit
: 6/12/2015
As the Windows program is too large to be uploaded on this forum, you can download it from here: B4Multingual.v1

Installation: Uncompress the zip file on your computer. A folder, B4Multilingual, will be created. Double click on the executable B4Multilingual.exe to start the program.

For details on how to use the library see this post, but be aware the library posted there is obsolete. For a tutorial on how to generate code, see post #2.

Edit: 13/12/2015
Support for resource folders and strings.xml files.

Download B4Multilingual.v1.1 (hosted externally) and the matching BAJLocaleDemoXML.v1.zip & BAJLocaleLibrary.v1.2.zip below.

See post #3 for details.
 

Attachments

  • BAJLocaleLibrary.v1.1.zip
    44.9 KB · Views: 204
  • BAJLocaleDemo.v1.zip
    11.8 KB · Views: 193
  • BAJLocaleDemoXML.v1.zip
    14.9 KB · Views: 212
  • BAJLocaleLibrary.v1.2.zip
    45 KB · Views: 245
Last edited:

cimperia

Active Member
Licensed User
Longtime User
I have posted in my first post the tools necessary to develop multi-language applications.

In this second post I’ll show how to generate the code for a B4(A/J) class. We’ll assume that you’ve added the keys required for your application, that you have selected the languages you want to cater for and that finally you generated the translations. I’ll describe those steps in a further post, but here I mean to describe how to use the end product so you realize how convenient it is. The database is pre-populated so that you can follow the example immediately.

Startup B4Multingual.

24ox24k.jpg


There’s already one application in the database: BAJLocaleDemo.

Double click on the row header (>) and a new tab [BAJLocaleDemo] gets added and displays all translations that were generated previously (and as I mentioned that I’ll describe later on.)

mcq1yb.jpg


Click on the utmost right icon to Generate a BA class. Once the code has been generated a window Generated B4A Code will pop up. Click on the icon to Copy the code to the clipboard, i.e. Windows memory buffer.

v33cea.jpg


You can now open the B4A application BAJLocaleDemo and replace the code of the Tr class by pasting the one in the clipboard. You can then compile and run the application.

1y94b7.jpg


If you change the language of your device to Italian, via the application, you should see this:
10fe54g.jpg


Next post I'll describe more of the program functionality.
 

cimperia

Active Member
Licensed User
Longtime User
(Download B4Multilingual.v.1.1, BAJLocaleDemoXML.v1.zip & BAJLocaleLibrary.v1.2.zip from post #1)

In this third post I’ll show how to generate the resource folders and strings.xml files for an XML/B4A based localized project. It is not suitable, yet, for a B4J project as a Java application uses Properties for i18n. A later release of B4Multilingual will cater for that. The version 1.2 of the BAJLocale library is compatible with B4J though, if you use the implementation described in post #2. I’ll post in a few days a B4J demo with the library recompiled (with no code change) as a B4J library.

From the B4A application point of view (BAJLocaleDemoXML), whether it uses the all-b4A implementation or the xml + b4A class, there is no difference, as you can see in the application main activity. The generated code takes care of that.

All it takes in 'main' is to reference the TrXML class of which code is generated by B4Multilingual.

One last point regarding running BAJLocaleDemoXML. The demo does not allow the changing of locales via the spinner. It has to be done through your device (or more likely emulator settings). This is so that the plural feature works.

B4X:
Sub Globals
#If XML
  Dim oTr  AsTrXML
#Else
  Private oTr AsTr
#End If
'''

If you wish to revert to pure B4A code as described in post #2, in the BAJLocaleDemoXML app, click on Project | Build Configurations and rename the XML conditional Symbols to something different. The demo will run unchanged. Please refer to post #2 for details.

efp6py.jpg


The advantages of using an XML approach for localization, is that in theory, you could add support for extra languages without having to recompile your Android app. You would just need to add the extra resource folder and strings.xml, folder value-es for Spanish for example, and your application would run unchanged. The reality is that you have to re-test thoroughly for every added locale as the text might not display as you expected because of its unexpected length, and therefore some UI modification is sometimes required.

The other advantage is that Android will handle singular and plural values with ease. The Singular and plural concepts are a thorny issue as not all languages share the exact rules about what they represent.

While English and many other languages distinguish between singular and plural nouns, for example, others, like Japanese and Chinese, do not


Installation:
(Download B4Multilingual.v.1.1, BAJLocaleDemoXML.v1.zip & BAJLocaleLibrary.v1.2.zip from post #1)

First install B4Multingual V1.1 (see post #1 for details), then install the B4A application BAJLocaleDemoXML. Copy the version 1.2 of the library (BAJLocale.jar/xml) in your B4A shared library folder.

As in the previous post the demo database is pre-populated for convenience.

The settings are as follows:
  • The default language is English
  • Two locales have been selected: Italian & French
  • Translations were automatically generated through Microsoft Bing web service.
Launch B4Multingual.

1zezjvk.jpg


There’s already one application in the database: BAJLocaleDemo.

Double click on the row header (>) and a new tab [BAJLocaleDemo] gets added and displays all translations that were generated previously.

Click on this new tab. All translations show up.
Click on the Code Generation Settings icon

2r53yas.jpg


and the following form gets displayed.

Make sure that XML file, Lower case & Generate Extra Localization are checked.

331dkrp.jpg


Close the form.

Click on the utmost right icon to generate the XML files and resource folders.

2ccx7pv.jpg


Once the folders and the strings.xml files have been created, the following Information window will display. It explains what was generated and what to do with it.

20tjjex.jpg


A folder called after the selected project name, all lower case, will be created in the folder where B4Multilingual is installed. In our demo, the folder is called bajlocaledemo.

There always will be one folder for the default language, which is always named value and an extra folder for every locale selected: Italian and French in this particular instance.

Copy all the folders and

258sefa.jpg


paste them in BAJLocaleDemoXML\ Objects\res directory.

Click the OK button, in the window that displays info about folders, to generated some B4A code.

Once the code has been generated a window titled Generated B4A Code will pop up. Click on the icon to Copy the code to the memory buffer.

v5ycuo.jpg



Paste it in the TrXML class, replacing all its code. Compile and run.

28lykwj.jpg


strings.xml file for default/master language.
B4X:
<?xml version="1.0" encoding="utf-8"?>
<!--English:Default Language-->
<!--en-->
<resources>
  <string name="clubs">"Clubs"</string>
  <string name="currency">"Currency"</string>
  <string name="currency_symbol">"Currency Symbol"</string>
  <string name="current_language">"Current Language"</string>
  <string name="diamonds">"Diamonds"</string>
  <string name="first_week_day">"First day of week"</string>
  <string name="hearts">"Hearts"</string>
  <string name="planets">"Planets"</string>
  <string name="select_lang">"Select Language"</string>
  <string name="select_month">"Select Month"</string>
  <string name="select_weekday">"Select Weekday"</string>
  <string name="spades">"Spades"</string>
  <string name="suits">"Suits"</string>
  <string name="title">"Title"</string>
  <string name="trans_with_var_values">"Translation with variable values"</string>
  <string name="variable_message">"You are in %1$s and your Currency is %2$s"</string>
  <string-array name="planets_a">
    <item>"Mercury"</item>
    <item>"Venus"</item>
    <item>"Earth"</item>
    <item>"Mars"</item>
    <item>"Jupiter"</item>
    <item>"Saturn"</item>
    <item>"Uranus"</item>
    <item>"Neptune"</item>
  </string-array>
  <plurals name="car_p">
    <item quantity="one">"car"</item>
    <item quantity="other">"cars"</item>
  </plurals>
</resources>

Doc of generated class to handle the resources folders.
TrXML (Class)
Properties:

  • AJCalendar As ajcalendar [read only]
  • AJCurrency As ajcurrency
  • AJDateFormat As ajdateformat [read only]
  • AJDateFormatSymbols As ajdateformatsymbols [read only]
  • AJLocale As ajlocale
  • AJResources As ajresources [read only]
  • clubs As String [read only]
  • currency As String [read only]
  • currency_symbol As String [read only]
  • current_language As String [read only]
  • diamonds As String [read only]
  • first_week_day As String [read only]
  • hearts As String [read only]
  • planets As String [read only]
  • planets_aMap As Map [read only]
  • select_lang As String [read only]
  • select_month As String [read only]
  • select_weekday As String [read only]
  • spades As String [read only]
  • suits As String [read only]
  • title As String [read only]
  • trans_with_var_values As String [read only]
  • variable_message As String [read only]
Methods:
  • IsInitialized As boolean
    Tests whether the object has been initialized.
  • getcar_pMap (HowMany As int) As String
  • Initialize (ba As BA) As String
 
Top