0
votes

I have a Xamarin Form application which has a language dropdown so user can select the application language. When user select a language I call:

            CultureInfo culture = CultureInfo.CreateSpecificCulture(language);
            System.Globalization.CultureInfo.CurrentUICulture = culture;
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;
            AppResources.Culture = culture;

The application works fine and picks the strings from AppResources.{language}.resx My problem is when localising an image. As per Microsoft's suggestion I have added my image to Resources/drawable folders inside the android project. In my case, I added thanks.jpg to Resources/drawable and Resources/drawable-fr. But it only shows the image on Resources/drawable folder even when I select fr-FR as language, however I found out if instead of changing the application language(culture), I change the device language, the device show the correct image(the image inside Resources/drawable-fr). I was wondering if there is any way to fix this issue.

1

1 Answers

2
votes

You can create a dependence service to fix it.

First of all, create a interface.

    public interface IChangeService
    {
        void ChangeIanguage(string lang);
    }

We used it in the this format code in the xamarin forms.

  <StackLayout>
        <TimePicker></TimePicker>
        <Image WidthRequest="100">
            <Image.Source>
                <OnPlatform x:TypeArguments="ImageSource">
                    <On Platform="iOS, Android" Value="flag.png" />
                    <On Platform="UWP" Value="Assets/Images/flag.png" />
                </OnPlatform>
            </Image.Source>
            </Image>
            <Button Text="Change" Clicked="Button_Clicked"></Button>
    </StackLayout>

Here is background code.

 public partial class LocalizedXamlPage : ContentPage
    {
        public LocalizedXamlPage()
        {
            InitializeComponent();
        }

        private void Button_Clicked(object sender, System.EventArgs e)
        {
            DependencyService.Get<IChangeService>().ChangeIanguage("en");
        }
    }

Then achieve the interface in the android platform. If we change the localization, we need it to work at the runtime, we should restart our application.

[assembly: Dependency(typeof(ChangeLanguageService))]
namespace UsingResxLocalization.Droid
{
    public class ChangeLanguageService : IChangeService
    {
        public void ChangeIanguage(string lang = "in")
        {
           
            LanguageManager.ChangeLanguage(MainActivity.instance, lang);
            //restart your application.
            Intent intent = new Intent(MainActivity.instance, typeof(MainActivity));
            intent.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
            MainActivity.instance.StartActivity(intent);
        }
    }
}

Then we need to create a BaseActivity(because we change the Locale in android, we should use the same Context.) and LanguageManager(change the localization at the runtime)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
using Java.Util;
using Xamarin.Forms.Platform.Android;

namespace UsingResxLocalization.Droid
{
    public class BaseActivity : FormsAppCompatActivity
    {
        protected override void AttachBaseContext(Context @base)
        {
            base.AttachBaseContext(LanguageManager.LoadLanguage(@base));
        }

    }

    public class LanguageManager
    {
        private const string MYLANGUAGE = "myLanguage";
        private const string MYPREF = "myPreference";

        public static Context LoadLanguage(Context context)
        {
            var loadedLanguage = GetLanguage(context, Locale.Default.Language);
            return ChangeLanguage(context, loadedLanguage);
        }

        public static Context ChangeLanguage(Context context, string language)
        {
            SaveLanguage(context, language);
            if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
            {
                return ChangeForAPI24(context, language);
            }
            return ChangeForLegacy(context, language);
        }

        private static string GetLanguage(Context context, string Language)
        {
            var privatePreference = context.GetSharedPreferences(MYPREF, FileCreationMode.Private);
            return privatePreference.GetString(MYLANGUAGE, Language);
        }

        private static void SaveLanguage(Context context, string language)
        {
            var privatePreference = context.GetSharedPreferences(MYPREF, FileCreationMode.Private);
            var editor = privatePreference.Edit();
            editor.PutString(MYLANGUAGE, language);
            editor.Apply();
        }

        private static Context ChangeForAPI24(Context context, string language)
        {
            // for api >= 24
            var locale = new Locale(language);
            Locale.Default = locale;
            var configuration = context.Resources.Configuration;
            configuration.SetLocale(locale);
            configuration.SetLayoutDirection(locale);

            return context.CreateConfigurationContext(configuration);
        }

        private static Context ChangeForLegacy(Context context, string language)
        {
            var locale = new Locale(language);
            Locale.Default = locale;
            var resources = context.Resources;
            var configuration = resources.Configuration;
            configuration.Locale = locale;
            resources.UpdateConfiguration(configuration, resources.DisplayMetrics);
            return context;
        }
    }
}

To make the mainAcitvity extend the BaseActivity.cs. And expose the public static MainActivity instance;,

 [Activity(Label = "UsingResxLocalization", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : BaseActivity
    {
        public static MainActivity instance;
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            instance = this;
            base.OnCreate(savedInstanceState);

            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
    }

Here is runinng GIF.

enter image description here

========Update=========

I make a test with France flag by changing language to fr when the device language is English.

I upload my demo to you, you can test it.

https://github.com/851265601/LocalzationDemo/blob/master/LocalzationDemoWithFlag.zip

If you want to change the text of Button or other label, when you click the Button, Please add CultureInfo.CurrentUICulture = new CultureInfo("fr", false); as well in the click event. You can see this GIF.

enter image description here