Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Localizing Xamarin.Forms with Hindi Language

4.33/5 (2 votes)
24 Apr 2016CPOL5 min read 12.5K  
How to localize Xamarin.Forms with Hindi Language

India is a very versatile country with 23 constitutionally recognized official languages ?? out of those 9 are can be found in the MS Global list of languages codes used in providing localization to applications. What can be the best way to provide example of localization in Xamarin forms than to provide an example to which all Indians can relate to ?? our national language Hindi as the default documentation of Xamarin Forms provides examples in all the other languages ?? except Hindi.

The built-in mechanism for localizing .NET applications uses RESX files and the classes in the System.Resources and System.Globalization namespaces. The RESX files containing translated strings are embedded in the Xamarin.Forms assembly, along with a compiler-generated class that provides strongly-typed access to the translations. The translation text can then be retrieved in code.

The implementation of the same in Xamarin Forms will have to be done in the platform specific code and invoke the same in portable class using Dependency Service.

Let's start coding ??. Create a new project in Xamarin/Visual Studio (see this article for steps). Add a new folder named ‘Resx’ by right clicking on the PCL project file and Selecting ‘Add’ –> ‘Add Folder’ Option. This folder will be used to save the resource files to implementing localization, you can name it something else also but giving the name ‘Resx’ will give more clarity in understanding the purpose of the folder.

Create a new resource file inside the ‘Resx’ folder with name ‘AppResources.resx’ by right clicking on the folder then selecting Add –> New Item –> Visual C# –> Resource File. This will be the default resource file which will be used by the application in the absence of any other resource files and will contain the English language implementation for the resource keys. The file will look like the following screenshot:

English Resource File
Create another resource file inside ‘Resx’ folder with name ‘AppResources.hi.resx’ by following the same above mentioned steps. This resource file will be used to store the resource keys values for Hindi language. This file will look like the following screenshot:

Hindi Resource File

Similarly you can add resource files for other languages using the code provided in MS Global list of languages like ‘AppResources.<language code="">.resx’. For example Gujrati –> ‘AppResources.gu.resx’ or Sanskrit –> ‘AppResources.sa.resx’ or Punjabi — > ‘AppResources.pa.resx’, etc.

Create the interface whose methods will be implemented in platform specific codes and invoked in PCL using dependency service. The code of the interface will look like:

C#
using System.Globalization;
namespace HindiXamApp
{
    public interface ILocalize
    {
        CultureInfo GetCurrentCultureInfo();
        CultureInfo GetCurrentCultureInfo(string sLanguageCode);
        void SetLocale();
        void ChangeLocale(string sLanguageCode);
    }
}

The first method of the interface ‘GetCurrentCultureInfo’ is for getting default culture info of the device, the second one ‘GetCurrentCultureInfo(string sLanguageCode)’ is for getting culture info on the basis of provided language code, the third method ‘SetLocale’ is used to set the default culture info on the basis of value got from ‘GetCurrentCultureInfo’ and ‘ChangeLocale(string sLanguageCode)’ is to change the culture info of application on the basis of provided language code.

I have named the implementation class of the above interface as ‘LocaleService’ in all the platforms.The code for iOS implementation for the interface methods will be like:

C#
using System;
using System.Globalization;
using System.Threading;

using Foundation;
using Xamarin.Forms;

[assembly: Dependency(typeof(HindiXamApp.iOS.LocaleService))]
namespace HindiXamApp.iOS
{
    public class LocaleService : ILocalize
    {
        public CultureInfo GetCurrentCultureInfo()
        {
            var iosLocaleAuto = NSLocale.AutoUpdatingCurrentLocale.LocaleIdentifier;    // en_FR
            var iosLanguageAuto = NSLocale.AutoUpdatingCurrentLocale.LanguageCode;      // en
            var netLocale = iosLocaleAuto.Replace("_", "-");
            const string defaultCulture = "en";

            CultureInfo ci = null;
            if (NSLocale.PreferredLanguages.Length > 0)
            {               
                try
                {
                    var pref = NSLocale.PreferredLanguages[0];
                    var netLanguage = pref.Replace("_", "-");
                    ci = CultureInfo.CreateSpecificCulture(netLanguage);
                }
                catch
                {
                    ci = new CultureInfo(defaultCulture);
                }
            }
            else
            {
                ci = new CultureInfo(defaultCulture); // default, shouldn't really happen :)
            }
            return ci;
        }
        public CultureInfo GetCurrentCultureInfo(string sLanguageCode)
        {
            return CultureInfo.CreateSpecificCulture(sLanguageCode);
        }
        public void SetLocale()
        {
            var ci = GetCurrentCultureInfo();
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
            Console.WriteLine("SetLocale: " + ci.Name);
        }
        public void ChangeLocale(string sLanguageCode) {
            var ci = CultureInfo.CreateSpecificCulture(sLanguageCode);
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
            Console.WriteLine("ChangeToLanguage: " + ci.Name);
        }      
    }
}

The code for Android implementation will be like:

C#
using System;
using System.Globalization;
using System.Threading;
using Xamarin.Forms;

[assembly: Dependency(typeof(HindiXamApp.Droid.LocaleService))]
namespace HindiXamApp.Droid
{
    public class LocaleService : ILocalize
    {
        public CultureInfo GetCurrentCultureInfo()
        {
            var androidLocale = Java.Util.Locale.Default; // user's preferred locale
            var netLocale = androidLocale.ToString().Replace("_", "-");

            #region Debugging output
            Console.WriteLine("android:  " + androidLocale.ToString());
            Console.WriteLine("netlang:  " + netLocale);

            var ci = new CultureInfo(netLocale);
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
            Console.WriteLine("thread:  " + Thread.CurrentThread.CurrentCulture);
            Console.WriteLine("threadui:" + Thread.CurrentThread.CurrentUICulture);
            #endregion

            return ci;
        }
        public CultureInfo GetCurrentCultureInfo(string sLanguageCode)
        {
            return CultureInfo.CreateSpecificCulture(sLanguageCode);
        }
        public void SetLocale()
        {
            var ci = GetCurrentCultureInfo();
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }
        public void ChangeLocale(string sLanguageCode)
        {
            var ci = CultureInfo.CreateSpecificCulture(sLanguageCode);
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
            Console.WriteLine("ChangeToLanguage: " + ci.Name);
        }
    }
}

Since we are also going to use the values of resource files in XAML, we will have to write XAML extension to read the values from resource files. So create a new class by the name of ‘TranslateExtension’ and copy the following code inside it.

C#
using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace HindiXamApp
{
    [ContentProperty("Text")]
    public class TranslateExtension : IMarkupExtension
    {
        readonly CultureInfo ci;
        const string ResourceId = "HindiXamApp.Resx.AppResources";

        public TranslateExtension()
        {
            if (string.IsNullOrEmpty(App.CultureCode))
            {
                ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
            }
            else ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo(App.CultureCode);
        }

        public string Text { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Text == null)
                return "";

            ResourceManager temp = new ResourceManager
            (ResourceId , typeof(TranslateExtension).GetTypeInfo().Assembly);
            var translation = temp.GetString(Text, ci);
            if (translation == null)
            {
#if DEBUG
                throw new ArgumentException(string.Format("Key '{0}' was not found 
                in resources '{1}' for culture '{2}'.", Text, ResourceId, ci.Name), "Text");
#else
				translation = Text; // HACK: returns the key, which GETS DISPLAYED TO THE USER
#endif
            }
            return translation;
        }
    }
}

This completes the translation related code changes of the application, now let's create the UI of the application. The application will have a Xamarin Forms ContentPage which will have picker containing list of languages and table containing some static values.The static values of the table will by default appear in English and when the user selects ‘हिन्दी’ from the picker, the content will change to Hindi. I want to give user the freedom to choose the language in app rather than changing the language from device settings. That's the reason why I added ‘GetCurrentCultureInfo(string sLanguageCode)’ and ‘ChangeLocale(string sLanguageCode)’ in the code. The XAML code of the ‘HomePage’ is as follows:

XML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:lEx="clr-namespace:HindiXamApp;assembly=HindiXamApp"
             x:Class="HindiXamApp.HomePage">
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" />
  </ContentPage.Padding>
  <ContentPage.Content>
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="10"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="10"/>
      </Grid.ColumnDefinitions>
      <Label Grid.Row ="0" Grid.Column="1" 
      Text="{lEx:Translate SelectLanguage}" />
      <Picker  Grid.Row="0" Grid.Column="2" 
      x:Name="pkrLanguage" 
		SelectedIndexChanged="OnPickerChanged" 
		WidthRequest="50" >
        <Picker.Items>
          <x:String>English</x:String>
          <x:String>हिन्दी</x:String>
        </Picker.Items>
      </Picker>
      <Label Grid.Row ="1" Grid.Column="1" 
      Text="{lEx:Translate Name}" />
      <Label Grid.Row="1" Grid.Column="2"  
      Text ="{lEx:Translate NameValue}" />
      <Label Grid.Row ="2" Grid.Column="1" 
      Text="{lEx:Translate DateOfBirth}" />
      <Label Grid.Row="2" Grid.Column="2" 
      Text ="{lEx:Translate DOBValue}"/>
      <Label Grid.Row ="3" Grid.Column="1" 
      Text="{lEx:Translate Gender}" />
      <Label Grid.Row="3" Grid.Column="2" 
      Text ="{lEx:Translate GenderValue}"/>
      <Label Grid.Row ="4" Grid.Column="1" 
      Text="{lEx:Translate Address}"  />
      <Label Grid.Row="4" Grid.Column="2" 
      Text ="{lEx:Translate AddressValue}" />
      <Label Grid.Row ="5" Grid.Column="1" 
      Text="{lEx:Translate State}"  />
      <Label Grid.Row="5" Grid.Column="2" 
      Text ="{lEx:Translate StateValue}" />
      <Label Grid.Row ="6" Grid.Column="1" 
      Text="{lEx:Translate Country}"/>
      <Label Grid.Row="6" Grid.Column="2" 
      Text ="{lEx:Translate CountryValue}" />
    </Grid>   
  </ContentPage.Content>
</ContentPage>

As it can be seen from the above code, we are using ‘{lEx:Translate HomeButtonXaml}’ to set the text of the variables on the basis of resource file values and lEx: is declared as local namespace xmlns:lEx=”clr-namespace:HindiXamApp;assembly=HindiXamApp”. This basically lets us use the above declared Translate XAML extension.

The code written in code behind of ‘HomePage’, which contains the implementation of language change is as follows:

C#
using System;
using Xamarin.Forms;

namespace HindiXamApp
{
    public partial class HomePage : ContentPage
    {
        public HomePage()
        {
            InitializeComponent();
        }

        public void OnPickerChanged(object sender, EventArgs args)
        {
            var vSelectedValue = pkrLanguage.Items[pkrLanguage.SelectedIndex];
            if (vSelectedValue.Trim() == "हिन्दी")
            {
                DependencyService.Get<ILocalize>().ChangeLocale("hi");
                App.CultureCode = "hi";
            }
            else
            {
              DependencyService.Get<ILocalize>().SetLocale();
              App.CultureCode = string.Empty;
            }
            var vUpdatedPage = new HomePage();
            Navigation.InsertPageBefore(vUpdatedPage, this);
            Navigation.PopAsync();
        }
    }
}

As it can be seen from the above code, we are changing the culture of the application in ‘OnPickerChanged’ event using dependency service code ‘DependencyService.Getilocalize().ChangeLocale(“hi”);’. After that, we are setting the value of application level static variable ‘App.CultureCode’ so that translate extension should be able to get the respective culture info from platform and lastly, we are creating a new object of home page and adding it to Navigation stack as updated culture info won’t work on the existing page object because its resources are already loaded. I have implemented an if statement as I am showing the example for only 2 languages. If you are giving options for more languages, I suggest to use switch statement.

This is how the application will look on execution:

iOS Simulator:

iOS Example

Click here to watch video

Android Simulator:

Click here to watch video

I have just implemented the one aspect of implementing localization, i.e., user Interface localization, but in order to make the application completely localized, the database of the application should also support that which will change depending upon the need/requirements of the application. This application right now only supports Hindi, however I would request everyone who knows/understands the other nine Indian languages to fork the code on Github, add the resource file of those languages so that we could share the example containing all the Indian languages. :).You can use this translator which I used to write Hindi. Let me know if I have missed anything or you have any queries/suggestions.

?? Happy coding! ??

Reference: Official Xamarin Forms Documentation.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)