Here's a short tutorial showing how you can add support for multiple languages to your B4A application using my AndroidResources library.
Native Android applications have built in support for multiple languages.
Instead of hardcoding text that will be displayed into your program code, you instead hardcode a reference to a string resource.
You define a default value for the string resource and can add one or more definitions for the same string resource - one definition for each language that you want to support.
If a device running your application is set to use a language that has a string resource defined then that string resource is used, otherwise the default string resource is used.
Some useful links that you might want to read:
Please read those links so that you understand how Android uses differently name values folders to contain string resource values for different languages.
So you need to create one or more XML files that define string resource values, these XML files must be placed in your project's Objects/res/values and optionally Objects/res/values-?? folders.
(The names of your XML files are by tradition strings.xml but you can use any other filenames if you desire.)
Do not forget to set your XML files to read-only otherwise the B4A compiler will delete them when it compiles your application.
Your application's default string resources are defined in Objects/res/values, here's an example XML file that defines English values:
Let's add support for both French and German languages.
Resource file location: Objects/res/values-de:
Resource file location: Objects/res/values-fr:
You can see here that some characters require special treatment in your XML files.
There's various ways to escape individual characters, but here i've used 2 techniques to properly encode the entire string value:
You now have three well formed XML files defining string resources for:
We'll use the AndroidResources GetApplicationStrings method to get the required values into our B4A code:
GetApplicationStrings (ResourceNames As Map) As Map
Get one or more application resource Strings.
Pass a Map to this method where each Map key is an application String resource name.
The method will return the same Map object where the Map values are the application resource Strings defined by the Map keys.
If an application resource String is not found the Map value will not be changed.
A simple B4A Activity:
The layout file Main.bal contains just a Panel containing Label1 and Button1 placed under the Panel.
No Text values are defined in the layout file - Label1.Text and Button1.Text are blank.
The ResourceStrings Map object keys are the names of the defined string resources we want to retrieve.
The Map object is passed to the GetApplicationStrings method.
AndroidResources searches for the requested string resource, if the string resource is found then it's value is set as the corresponding Map value.
If a requested string resource is NOT found the corresponding Map value is left unchanged.
Change your device's default language via Settings > Language & keyboard to see the different string resources display.
There's room for improvement on this example code...
If you Activity contains many Views you might want to find a way to iterate those Views and set their Text values.
Another possible improvement would be to automate the entire process...
Could a Label or Button's Tag property be set in Designer to the name of a string resource and then code created to get all Views with Tags that refer to a string resource and the string resource value automatically set as the View's Text property?
Localization isn't just about strings of course, you can define other language dependent resources such as those defined in Objects/res/drawable.
AndroidResources has GetApplicationDrawable and GetApplicationDrawables methods which you can use to localize images displayed in your application.
Demo code attached, please get the latest version of the AndroidResources library from the AndroidResources thread.
Martin.
Native Android applications have built in support for multiple languages.
Instead of hardcoding text that will be displayed into your program code, you instead hardcode a reference to a string resource.
You define a default value for the string resource and can add one or more definitions for the same string resource - one definition for each language that you want to support.
If a device running your application is set to use a language that has a string resource defined then that string resource is used, otherwise the default string resource is used.
Some useful links that you might want to read:
Please read those links so that you understand how Android uses differently name values folders to contain string resource values for different languages.
So you need to create one or more XML files that define string resource values, these XML files must be placed in your project's Objects/res/values and optionally Objects/res/values-?? folders.
(The names of your XML files are by tradition strings.xml but you can use any other filenames if you desire.)
Do not forget to set your XML files to read-only otherwise the B4A compiler will delete them when it compiles your application.
Your application's default string resources are defined in Objects/res/values, here's an example XML file that defines English values:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="continue_text">Continue</string>
<string name="intro_text">Welcome to the localization demo Activity.</string>
<string name="main_activity_title">Localize your application</string>
</resources>
Let's add support for both French and German languages.
Resource file location: Objects/res/values-de:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="continue_text">Fortsetzen</string>
<string name="intro_text" formatted="false">Willkommen bei der Lokalisierung Demo Aktivität.</string>
<string name="main_activity_title">"Lokalisieren Sie Ihre Anwendung"</string>
</resources>
Resource file location: Objects/res/values-fr:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="continue_text">Continuer</string>
<string name="intro_text">"Bienvenue à l'activité de démonstration de localisation."</string>
<string name="main_activity_title">Localisez votre demande</string>
</resources>
You can see here that some characters require special treatment in your XML files.
There's various ways to escape individual characters, but here i've used 2 techniques to properly encode the entire string value:
- You can contain the entire string value within double quotes:
<string name="intro_text">"Bienvenue à l'activité de démonstration de localisation."</string> - Or you can add the formatted="false" attribute to the string tag:
<string name="intro_text" formatted="false">Willkommen bei der Lokalisierung Demo Aktivität.</string>
You now have three well formed XML files defining string resources for:
- The device's default language.
- The French language.
- The German language.
We'll use the AndroidResources GetApplicationStrings method to get the required values into our B4A code:
GetApplicationStrings (ResourceNames As Map) As Map
Get one or more application resource Strings.
Pass a Map to this method where each Map key is an application String resource name.
The method will return the same Map object where the Map values are the application resource Strings defined by the Map keys.
If an application resource String is not found the Map value will not be changed.
A simple B4A Activity:
B4X:
'Activity module
Sub Process_Globals
End Sub
Sub Globals
Dim AndroidResources1 As AndroidResources
Dim Button1 As Button
Dim Label1 As Label
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Main")
Dim ResourceStrings As Map
ResourceStrings.Initialize
ResourceStrings.Put("continue_text", "Error, resource string not found")
ResourceStrings.Put("intro_text", "Default intro text")
ResourceStrings.Put("main_activity_title", "Default activity title")
ResourceStrings=AndroidResources1.GetApplicationStrings(ResourceStrings)
Activity.Title=ResourceStrings.Get("main_activity_title")
Button1.Text=ResourceStrings.Get("continue_text")
Label1.Text=ResourceStrings.Get("intro_text")
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Button1_Click
' to do, start a new Activity
End Sub
The layout file Main.bal contains just a Panel containing Label1 and Button1 placed under the Panel.
No Text values are defined in the layout file - Label1.Text and Button1.Text are blank.
The ResourceStrings Map object keys are the names of the defined string resources we want to retrieve.
The Map object is passed to the GetApplicationStrings method.
AndroidResources searches for the requested string resource, if the string resource is found then it's value is set as the corresponding Map value.
If a requested string resource is NOT found the corresponding Map value is left unchanged.
Change your device's default language via Settings > Language & keyboard to see the different string resources display.
There's room for improvement on this example code...
If you Activity contains many Views you might want to find a way to iterate those Views and set their Text values.
Another possible improvement would be to automate the entire process...
Could a Label or Button's Tag property be set in Designer to the name of a string resource and then code created to get all Views with Tags that refer to a string resource and the string resource value automatically set as the View's Text property?
Localization isn't just about strings of course, you can define other language dependent resources such as those defined in Objects/res/drawable.
AndroidResources has GetApplicationDrawable and GetApplicationDrawables methods which you can use to localize images displayed in your application.
Demo code attached, please get the latest version of the AndroidResources library from the AndroidResources thread.
Martin.