0

I'm trying to create an app that supports multilabel languages, in which I have a settings page that allows the user to chose a language, then the View Model would publish a message using the MessagingCenter, then finally, MainActivity would respond to this message

and that's the code sample for the above mentioned

private async void HandleSelectedLanguageChanged()
{
    if (SelectedLanguage == null || !this.isInitialized)
        return;

    MessagingCenter.Send(this, Constants.LanguageChanged, SelectedLanguage);
    ShowLoading(); 
    await Task.Delay(1000);
    await NavigationService.NavigateAsync($"/{Routes.Landing}/{CallbackPage ?? Routes.Login}");
    HideLoading();
}

MainAcitivty

CultureInfo.CurrentCulture = selectedCulture;
CultureInfo.CurrentUICulture = selectedCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = selectedCulture;
System.Threading.Thread.CurrentThread.CurrentUICulture = selectedCulture;

var selectedCulture = Common.Settings.Settings.CurrentCultureInfo.ToDescriptionString().Split('-');
if (selectedCulture.Length == 2)
{
    var selectedLang = selectedCulture[0];
    var selectedCountry = selectedCulture[1];
    var locale = new Java.Util.Locale(selectedLang, selectedCountry);
    Java.Util.Locale.Default = locale;

    var config = new Android.Content.Res.Configuration { Locale = locale };
    Resources.UpdateConfiguration(config, BaseContext.Resources.DisplayMetrics);
}

the code in the MainActivity was simplified for the purpose of this question there are some device specific cultural configurations that are not relevant to this question, also I made sure that selectedCulture contains the intended culture, the code of creating this object is irrelevant to this question.

The weird thing is, the culture is only changed for the first page I navigate to, and reverts back for every other page in the app. here's the code for the translation MarkupExtension that I use for this

[ContentProperty("Text")] public class BaseTranslateExtension : IMarkupExtension { private string _resourceId; private Type _assemblyType;

    public BaseTranslateExtension(string resourceId, Type assemblyType)
    {
        _resourceId= resourceId;
        _assemblyType = assemblyType;
    }
    public string Text { get; set; }

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

        ResourceManager resourceManager = new ResourceManager(_resourceId, _assemblyType.GetTypeInfo().Assembly);

        return resourceManager.GetString(Text, CultureInfo.CurrentCulture);
    }
}

the CurrentCulture seems to only be set to the new culture for the first page only, for every other page it's just the same old value, which is weird since it's a static property that I'm sure is not being set anywhere else in the code

Scarnet
  • 738
  • 2
  • 11
  • 36
  • You could create a `BaseActivity` and rewrite the method `attachBaseContext` .Which will been invoked before `OnCreate` .Then change the language in it . – Lucas Zhang Jan 13 '20 at 11:47
  • @LucasZhang-MSFT just tried that and it didn't work, the thing this, if I restarted the application the new culture loads just fine, the problem is that it doesn't seem to work at runtime – Scarnet Jan 13 '20 at 12:55
  • 1
    Check https://stackoverflow.com/questions/49380833/change-language-of-the-application-programmatically-without-refreshing-the-whole – Lucas Zhang Jan 13 '20 at 13:00
  • @LucasZhang-MSFT thanks, that kinds worked; however, it caused during recreation, the screen gets dark giving the impression that the app got crashed, it doesn't take long for the app to reload so in my case I could accept that effect, but others might not – Scarnet Jan 14 '20 at 12:22

1 Answers1

1

I don't have language strings in Android resources, but in (old?) resx files. Maybe that's why I could use the following solution: also set the cultures of the default thread.

string cultureCode = GetUserRequestedAppCultureCode(); // For example: "en-US".
var selectedCulture = new CultureInfo(cultureCode);
CultureInfo.DefaultThreadCurrentCulture = selectedCulture;
CultureInfo.DefaultThreadCurrentUICulture = selectedCulture;
CultureInfo.CurrentCulture = selectedCulture;
CultureInfo.CurrentUICulture = selectedCulture;

For Xamarin.Android it is sufficient to run this code at (each) app start only. You can also switch languages this way at runtime without the need of restarting your app.

SymboLinker
  • 884
  • 6
  • 15