Bug 16248 - Add Android.App.Application.CurrentCulture and CurrentUICulture properties
Summary: Add Android.App.Application.CurrentCulture and CurrentUICulture properties
Status: RESOLVED NOT_ON_ROADMAP
Alias: None
Product: Android
Classification: Xamarin
Component: General ()
Version: 4.8.x
Hardware: PC Windows
: Low normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2013-11-14 20:26 UTC by mark
Modified: 2013-11-18 13:51 UTC (History)
1 user (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NOT_ON_ROADMAP

Description mark 2013-11-14 20:26:55 UTC
Within the original .Net, there are always been the option to set the required CultureInfo for an application.  This is achieved using the DefaultThread option.  This works very well when making application for the international market.

However Xamarin for Android, does not have the same support. And it seems the only way I can mimic this action is to create a new instance of a CultureInfo on each page, and set the format of every control.

I believe this is a major omission in Xamarin for Android, and I guess iOS also. Hence I am reporting this as a bug, in the hope some one can fix this.
Comment 1 Jonathan Pryor 2013-11-15 08:16:34 UTC
> This is achieved using the DefaultThread option.

I am not familiar with this option. Can you provide a link to documentation?

Is it the CultureInfo.DefaultThreadCurrentCulture property?

http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.defaultthreadcurrentculture(v=vs.110).aspx

CultureInfo.DefaultThreadCurrentCulture was added in .NET 4.5. Xamarin.Android should contain it, but it will throw NotImplementedException:

https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Globalization/CultureInfo.cs#L1013

That aside....

> the only way I can mimic this action is to create a new instance of a CultureInfo
> on each page, and set the format of every control.

This sounds like an astoundingly bad idea, at least for the default case.

In the "default case", you use .axml files to provide layout, controls, and the values of strings. Using .axml files is very GREF friendly: you only take a GREF for controls that you actually need to use.

If you set the language of _every_ control in code, you will consume a GREF for each control that you pull in (e.g. Labels that otherwise wouldn't consume a GREF).

Using Android's Resource mechanism is a better way to handle localization, as Android will handle the string lookups for the user's current locale, and Android can do so without consuming a GREF.

> [an] option to set the required CultureInfo for an application.

If you _really_ want to ignore the User's default locale, you can add an Environment.txt file to your application, set its build action to AndroidEnvironment, and add e.g.

    LANG=en-US

This will set the LANG environment variable during process startup, overriding the default computed value based on Android's locale.

http://docs.xamarin.com/guides/android/advanced_topics/environment/

(Note that overriding LANG requires Xamarin.Android 4.10 or later.)
Comment 2 mark 2013-11-15 09:26:11 UTC
Hi Jonathan,

Just to clarify a few things, the use of the CultureInfo is not to do with the language.  But to do with how dates, numeric values and currencies are displayed.

The reason we need to do this for our app, is our app is a financial Point of Sales type app.  Where we need all the dates, and currency values to reflect the predefined settings of the central system, regardless of the locale in the device.  For example, in one of the resorts we provide software for, the "base" currency used is Indonesian Rupiah, but if the device had been set to use a locale of en-US, all the amounts and dates would be wrong.  Alternatively another hotel, just 2 miles away uses the same software, but as the majority of their guests are foreign, their base currency is US$.  

So the app must display the figures and dates based on the selected base currency, not what the Android locale is.  This is the whole point of the CultureInfo.

With regards to Thread Default culture only being valid from .Net 4.5, this is incorrect.  Our Windows application uses .Net Framework version 4.0, and that has the ability to set the default culture to use for the app. In fact I believe this option has been available in .Net since version 1.1.

The actual code I use, which works very well in the Windows app is.

CurrentState.CultureInfo = new CultureInfo(Settings.CultureCode);
Application.CurrentCulture = CurrentState.CultureInfo;
Thread.CurrentThread.CurrentUICulture = CurrentState.CultureInfo;
Thread.CurrentThread.CurrentCulture = CurrentState.CultureInfo;

With regards to setting the culture using the axml, I am not sure that is possible, as the required culture is a user defined setting held in a database  table.
Comment 3 Jonathan Pryor 2013-11-15 10:02:45 UTC
> Where we need all the dates, and currency values to reflect
> the predefined settings of the central system,

So this isn't a per-app locale, but determined at runtime (and thus setting LANG would not be appropriate).

> The actual code I use, which works very well in the Windows app is.
> 
> CurrentState.CultureInfo = new CultureInfo(Settings.CultureCode);
> Application.CurrentCulture = CurrentState.CultureInfo;
> Thread.CurrentThread.CurrentUICulture = CurrentState.CultureInfo;
> Thread.CurrentThread.CurrentCulture = CurrentState.CultureInfo;

That should work, except that there is no `Application.CurrentCulture` member.

How does it fail for you?

> With regards to setting the culture using the axml, I am not sure that is
> possible, as the required culture is a user defined setting held in a database 
> table.

I think I misinterpreted things. It's not so much that you want _all_ strings in the same language, it's that you want the formatting of _some_ strings in a server-specified locale (numbers, etc.). As such, I don't think you need to worry about .axml files or Android localization.
Comment 4 mark 2013-11-15 22:01:05 UTC
The issue is there is not Application.CurrentCulture, so I am unable to globally set the culture I need at an application level.  I must remember to set it for every activity, popup etc. etc.

I believe this is an omission, could Xamarin for Android, and I suspect, Camarin for iOS, not create a pseudo Application class, and allow us to set things like the CurrentCulture, than automatically apply it everywhere needed in the application.  After all this what .Net has done since version 1.1.
Comment 5 Jonathan Pryor 2013-11-18 13:51:10 UTC
> The issue is there is not Application.CurrentCulture,

For starters, I believe this statement is incorrect. MSDN states that Application.CurrentCulture is only for the current thread, not all threads:

http://msdn.microsoft.com/en-us/library/system.windows.forms.application.currentculture(v=vs.110).aspx

Furthermore, Application.CurrentCulture does not modify all threads, at least according to:

http://stackoverflow.com/a/93622/83444
http://social.msdn.microsoft.com/Forums/vstudio/en-US/0f5b92f3-e5df-4c5d-a9ae-3781865ebf4a/locale-of-threadpools-thread
http://stackoverflow.com/questions/468791/setting-currentculture-and-currentuiculture-of-an-application

> I must remember to set it for every activity, popup etc. etc.

I would further suggest that you _not_ do this. If you know that you need to use a specific culture, use one of the CultureInfo-aware method overloads and _explicitly_ provide the culture instead of using Thread.CurrentCulture/etc.

For example, instead of Int32.ToString(), use Int32.ToString(IFormatProvider) and provide the CultureInfo instance you need to use:

http://msdn.microsoft.com/en-us/library/cht2hdff(v=vs.110).aspx

    // BAD
    string s = Math.PI.ToString();

    // GOOD
    string s = Math.PI.ToString (MyDesiredCultureInfoInstance);

This is doubly useful if you don't control and/or review all code executing in your process. For example, if you use a 3rd party library which itself (1) uses the ThreadPool, and (2) sets Thread.CurrentCulture, that change could "leak" into your code, resulting in "impossible" scenarios ("I changed CurrentCulture on this thread already, why aren't I seeing my value?!") and the debugging headaches that will entail.

The best longer-term fix would be ThreadPool.DefaultThreadCurrentCulture, but that still wouldn't help with the above "3rd party lib changes my CultureInfo" scenario. Only using the CultureInfo-aware method overloads will help with that.