Saturday, 26 May 2018

Droid localization

In today's global market it is wise to offer your application in various languages to widen your target audience as much as possible, now it obviously doesn't make sense to make multiple versions of your application in various languages, so what to do instead? well every platform has some sort of Localization strategy and here we'll look at the one for Android.

first thing to make note of is our solution, specifically under the Resources->Values folder namely the strings file

now if we open that file, we'll see the following

<resources>
  <string name="app_name">Localization example</string>
  <string name="action_one">One</string>
  <string name="action_two">Two</string>
  <string name="action_three">Three</string>
  <string name="action_four">Four</string>
  <string name="value_userClicked">You clicked the button {0}</string>
</resources>

I've modified the original with some of my own values, next open up the axm file for the main activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
  a:layout_width="match_parent"
  a:layout_height="match_parent"
  a:orientation="vertical">
  <Button a:id="@+id/ButtonOne" a:text="@string/action_one"
          a:layout_width="fill_parent" a:layout_height="wrap_content"/>
  <Button a:id="@+id/ButtonTwo" a:text="@string/action_two"
          a:layout_width="fill_parent" a:layout_height="wrap_content"/>
  <Button a:id="@+id/ButtonThree" a:text="@string/action_three"
          a:layout_width="fill_parent" a:layout_height="wrap_content"/>
  <Button a:id="@+id/ButtonFour" a:text="@string/action_four"
          a:layout_width="fill_parent" a:layout_height="wrap_content"/>

</LinearLayout>

again I've also made some modifications, but make note of the highlighted sections in which we don't set the text value to a string, but to a reference into our strings file.


just to make things a bit interesting let's wire the apps up so that we get a toast message when we click our buttons.

using Android.App;
using Android.Widget;
using Android.OS;
using Android.Support.V7.App;
using System;

namespace pav.Localization
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            base.FindViewById<Button>(Resource.Id.ButtonOne).Click += Button_Click;
            base.FindViewById<Button>(Resource.Id.ButtonTwo).Click += Button_Click;
            base.FindViewById<Button>(Resource.Id.ButtonThree).Click += Button_Click;
            base.FindViewById<Button>(Resource.Id.ButtonFour).Click += Button_Click;
        }

        private void Button_Click(object sender, EventArgs e)
        {
            var self = sender as Button;
            var msg = base.Resources.GetString(Resource.String.value_userClicked);
            var toast = String.Format(msg, self.Text);

            Toast.MakeText(this,toast, ToastLength.Short).Show();
        }
    }
}

When we run our application and click one of our buttons we get the following


now it would be accurate to conclude that if we configured our application to get it's text data from a strings file, then all we'd need is string files for all of our various supported languages to create a multi lingual application.

so let's add a values-fr folder with it's own strings.xml file


and let's open up that strings file and create a french version

<resources>
  <string name="app_name">Exemple de localisation</string>
  <string name="action_one">Un</string>
  <string name="action_two">Deux</string>
  <string name="action_three">Trois</string>
  <string name="action_four">Quatre</string>
  <string name="value_userClicked">Vous avez cliqué sur le bouton {0}</string>
</resources>

notice that we only changed the element values and not the attributes, next if we run our application as is whether it's an emulator or an actual device we'll still see our original text, to switch to french we have to change the local of the actual phone


and voila


our application is not multi lingual, now let's do one last trick and that's let's internationalize some images. so let's add two folders into our solution explorer drawable and drawable-fr; in those folder let's add to images both named flag.png one a UK flag and the other a french flag.


now let's put an ImageView onto our axml file which whose src attribute points to our drawable->flag file.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
    a:layout_width="match_parent"
    a:layout_height="match_parent"
    a:orientation="vertical">
    <Button
        a:id="@+id/ButtonOne"
        a:text="@string/action_one"
        a:layout_width="fill_parent"
        a:layout_height="wrap_content" />
    <Button
        a:id="@+id/ButtonTwo"
        a:text="@string/action_two"
        a:layout_width="fill_parent"
        a:layout_height="wrap_content" />
    <Button
        a:id="@+id/ButtonThree"
        a:text="@string/action_three"
        a:layout_width="fill_parent"
        a:layout_height="wrap_content" />
    <Button
        a:id="@+id/ButtonFour"
        a:text="@string/action_four"
        a:layout_width="fill_parent"
        a:layout_height="wrap_content" />
    <ImageView
        a:src="@drawable/flag"
        a:layout_width="match_parent"
        a:layout_height="wrap_content" />

</LinearLayout>

and again depending on our language of choice our image changes