How to set Silverlight CurrentUICulture/CurrentCulture correctly? - c#

I'm working on a SL5 app with C# and I'm looking to internationalize it. I found the following to set the UI culture:
var culture = new CultureInfo(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName);
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
Some controls like the DatePicker seem to pick this up. If I format any datetime by using the 'd' format string, I still get the default format "M/dd/yyyy" however.
Exactly how does SL interpret culture and how can I set it correctly for the entire application?
Thanks
UPDATE:
Found the answer:
First of all, set the appropriate cultures in the Application_Startup:
var culture = new CultureInfo("nl-BE");
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
The key element however is to add the following to force the RootVisual's culture/language:
var root = RootVisual as Page;
if (root != null)
{
root.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
}

Edit: Updated with the information that #Rumble found.
You need to do it like this to apply it to your UI objects as well.
First set the appropriate cultures when your application is loading up.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-IN");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-IN");
Next you need to set the XML Language property.
For Silverlight
var root = RootVisual as Page;
if (root != null)
{
root.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
}
For WPF
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
You can find an explanation for WPF here.

Thanks to eandersson
I came up with this extension for specific controls.
I had a problem with my decimal input, parsing and validation. Somewhere in the way there was this InvariantCulture with '.' as separator instead of ','.
It can be easily modifed to set up specific culture.
public class ElementCultureExtension
{
public static bool GetForceCurrentCulture( DependencyObject obj )
{
return (bool)obj.GetValue( ForceCurrentCultureProperty );
}
public static void SetForceCurrentCulture( DependencyObject obj, bool value )
{
obj.SetValue( ForceCurrentCultureProperty, value );
}
public static readonly DependencyProperty ForceCurrentCultureProperty =
DependencyProperty.RegisterAttached(
"ForceCurrentCulture", typeof( bool ), typeof( ElementCultureExtension ), new PropertyMetadata( false, OnForceCurrentCulturePropertyChanged ) );
private static void OnForceCurrentCulturePropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e )
{
var control = (FrameworkElement)d;
if( (bool)e.NewValue )
{
control.Language = XmlLanguage.GetLanguage( Thread.CurrentThread.CurrentCulture.Name );
}
}
}
In Xaml:
<TextBox Text="{Binding Path=DecimalValue, Mode=TwoWay}"
tools:ElementCultureExtension.ForceCurrentCulture="True" />

Related

Change Language/Resource programmatically w/ WPF

I have a DropDown (using MahApps if that is important) that I'd like to use to switch the language "on the fly" in my program.
Language Class
namespace SAM
{
public class Language
{
public string Title { get; set; }
public string Culture { get; set; }
}
}
Change Language
private void DropLanguage_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
Language lang = DropLanguage.SelectedItem as Language;
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang.Culture);
}
I have all my strings as resources in Resources.resx (default) and Resources.en.resx (english)
3 issues I don't understand
When selecting "englisch" from the dropdown, the language does not change immediately but when I click sth. else, e.g. "close" (it asks "sure?"), the language has changed.
Strings that are directly in the .xaml file like <TextBlock Text="{x:Static p:Resources.Config_HeaderBar_Find_Speaker}" /> do not get updated at all.
Bonus: How would I switch back to the default language, as new CultureInfo(lang.Culture); expects one parameter and for the default I have Culture = null (as the Resources.resx has nothing in it's name). Changing the file to Resources.default.resx messes with my code a lot...
I tried to solve similar problem. The simplest solution for me was to move all Window content to UserControl and creating interface for window with method refreshLanguage(). Then I call from model:
private void SetLanguage(string cultureName)
{
var cul = new System.Globalization.CultureInfo(cultureName);
Properties.Resources.Culture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentCulture = cul;
InitializeHamburgerMenu();
MainWindowView.RegreshLanguage();
RaisePropertyChanged("Title");
}
And RefreshLanguage in Window looks like:
public void RegreshLanguage()
{
GlobalUserControl content = new GlobalUserControl("Views/SettingsPage.xaml");
ContentPresenter_GlobalUserControl.Content = content;
}
In my case, UserControl provides navigation, so I passed last navigated URI as parameter. So, if you need to preserve state you can pass it as parameter to new UserControl. Recreating usercontrol cause all strings to reload without window recreation. Maybe good idea would be to call GC.Collect(); here, but depends on your scenario.
About default neutral culture. For me works to call SetLanguage("").
There are 2 things
Thread.CurrentThread.CurrentCulture
and
Thread.CurrentThread.CurrentUICulture
In order to set these valuse use the static method
CultureInfo.GetCultureInfo(String langCode)
where some examples of the parameter langCode are the following strings
"de-DE"
"en-US"
etc.
more info at
https://msdn.microsoft.com/en-us/library/yck8b540(v=vs.110).aspx
So, overall these lines of code sould work for change in German Language:
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");

Right to left layout support

I'm trying to support Arabic language right to left layout support but turns out there is no way you can support right to left in Xamarin Forms.
I even tried dependency service and called right to left layout by myself. Here is the code:
public CultureInfo SetLocale(string locale)
{
var netLocale = locale.Replace("_", "-");
var ci = new CultureInfo(netLocale);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.JellyBeanMr1)
{
// Change locale settings in the app.
var dm = Forms.Context.Resources.DisplayMetrics;
var conf = Forms.Context.Resources.Configuration;
conf.Locale = new Java.Util.Locale(locale);
Forms.Context.Resources.UpdateConfiguration(conf, dm);
if (locale == "en")
(Forms.Context as MainActivity).Window.DecorView.LayoutDirection = Android.Views.View.LayoutDirectionLtr;
else
(Forms.Context as MainActivity).Window.DecorView.LayoutDirection = Android.Views.View.LayoutDirectionRtl;
}
return ci;
}
I hope I'm not too late, here are some links:
there is layoutDirection and on this forum they have answered it:
To detect when RTL is required, I use this bit of code (I found reflection was required, as the IsRightToLeft property was unexpectedly inaccessible):
bool rightToLeft = false;
PropertyInfo propertyInfo = thisCulture.TextInfo.GetType().GetRuntimeProperty("IsRightToLeft");
object value = propertyInfo?.GetValue(thisCulture.TextInfo);
if (value is bool)
rightToLeft = (bool) value;
After that, it was mostly a case of switching a few properties:
HorizontalOptions = rightToLeft ? LayoutOptions.EndAndExpand : LayoutOptions.StartAndExpand,
HorizontalTextAlignment = rightToLeft ? TextAlignment.End : TextAlignment.Start;
more links
Adjust layout and fonts, and support RTL
You could set the dir property of html if language is arabic.
<html dir="rtl">

Culture Not Being Set In App

I'm working on a WPF / C# app that needs to be culturally aware for globalization. I already have resource files and a bindable translation manager that is all working as expected.
At the moment I'm doing this:
Thread.CurrentThread.CurrentUICulture = _currentlyConfiguredUiCulture;
Thread.CurrentThread.CurrentCulture = _currentlyConfiguredUiCulture;
This is all wired up in the UI like this:
TranslationManager.Instance.LanguageChanged += TranslationManager_LanguageChanged;
private void TranslationManager_LanguageChanged(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = TranslationManager.Instance.CurrentLanguage;
Thread.CurrentThread.CurrentCulture = TranslationManager.Instance.CurrentLanguage;
}
This all works sweet!
The problem is when the app is started my machine locale is "en-GB" and this is correctly set using the code shown above. However, when I hit some code I have in an IValueConverter class dealing with dates:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return DateTime.Parse(value.ToString(), culture);
}
return null;
}
The culture property here is always "en-US" ... how on earth is this occurring? How do I fix this so that the app is actually using the correct system culture?
This link states that you might have to add the following:
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(
System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)));
If you created a thread, then the culture info is reset to the default one(for that thread). I think in .net 4.5 there might be a way to set the default thread cultureinfo.
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.defaultthreadcurrentculture.aspx

Can I use WPF window constructor to change culture?

I use the well known LocBaml approach to change culture.
It works fine here:
public App()
{
// Test code
bool override_current_ui_language = true;
string locale = "es-ES";
if (override_current_ui_language)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(locale);
Thread.CurrentThread.CurrentCulture = new CultureInfo(locale);
}
}
But when I use the same under WPF Window class controller it doesn't work.
Any clue why is it?
I use this but it doesn't work as well.
void cmbLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string locale = "es-ES";
Thread.CurrentThread.CurrentUICulture = new CultureInfo(locale);
Thread.CurrentThread.CurrentCulture = new CultureInfo(locale);
}
I use LocalizeExtension for that.
In the .xaml you just use {LocText NAMESPACE::RESOURCENAME} to set the text and in the code behind the following to change the language on the fly:
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
You can check my Project on Codeplex, where I use it, to see an extended example:
XAML and CodeBehind (->SetUICulture)
It should work in the constructor if you do it before the InitalizeComponent() call, but your example shows an event handler. Once InitializeComponent() is called the BAML has been loaded from the resources and you won't be able to change it.
You can use an approach like the one illustrated here https://www.codeproject.com/articles/29800/webcontrols/ to create a new window with your new culture:
void SwitchCulture(CultureInfo newCulture)
{
Thread.CurrentThread.CurrentUICulture = newCulture;
Thread.CurrentThread.CurrentCulture = newCulture;
// Reload all the merged dictionaries to reset the resources.
List<Uri> dictionaryList = new List<Uri>();
foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
{
dictionaryList.Add(dictionary.Source);
}
Application.Current.Resources.MergedDictionaries.Clear();
foreach (Uri uri in dictionaryList)
{
ResourceDictionary resourceDictionary1 = new ResourceDictionary();
resourceDictionary1.Source = uri;
Application.Current.Resources.MergedDictionaries.Add( resourceDictionary1 );
}
MyWindowClass newWindow = new MyWiondowClass();
// TODO: Attach any view model so the new window looks like the old one
newWindow.Show();
this.Close();
}

Setting Culture (en-IN) globally in WPF application

I have an application, which is based for India, and I'm setting Culture as:
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-IN");
The above code is called before the Window.InitializeComponent() method is called.
Still this is showing $ as CurrencySymbol in all TextBoxes.
If I bind a TextBox as following, it shows Rs. as CurrencySymbol:
Text="{Binding Salary,Mode=TwoWay,StringFormat=C,ConvertCulture=en-IN}".
I think you will need to add the following.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-IN");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-IN");
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
Read more here:
http://www.west-wind.com/weblog/posts/2009/Jun/14/WPF-Bindings-and-CurrentCulture-Formatting
Just to give you an example, this is how I initialize the Culture in my program, based on the user setting, but you can simply replace UserSettings.DefaultCulture and UserSettings.Default.UICultrue with your wanted Culture.
private static void InitializeCultures()
{
if (!String.IsNullOrEmpty(UserSettings.Default.Culture))
{
Thread.CurrentThread.CurrentCulture = new CultureInfo(UserSettings.Default.Culture);
}
if (!String.IsNullOrEmpty(UserSettings.Default.UICulture))
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(UserSettings.Default.UICulture);
}
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
For me just works, if i put this code to the OnStartup overrided method:
public partial class App : Application
{
public App()
{
}
protected override void OnStartup(StartupEventArgs e)
{
var vCulture = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = vCulture;
Thread.CurrentThread.CurrentUICulture = vCulture;
CultureInfo.DefaultThreadCurrentCulture = vCulture;
CultureInfo.DefaultThreadCurrentUICulture = vCulture;
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
base.OnStartup(e);
}
}
Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo.GetCultureInfo("en-IN");
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
This will switch the default language for the entire application. You’ll want to use this only in startup code as this setting can be applied only once per application. You can still override individual forms when necessary as below
this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
All WPF elements include a Language property that can be assigned and
determines the Culture that is used for formatting.
Reference
To me just this worked, but in order to solve ToString and to make it work over the entire app, it's important to add it in constructor, not OnStartup etc, before you set up service container etc. otherwise it doesn't work in subsequent threads and CultureInfo.CurrentUICulture still resolves to the default system CultureInfo.
public class App : Application
{
public App()
{
var culture = new CultureInfo("en-IN");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(culture.IetfLanguageTag)));
// should be before all this
var host = Host
.CreateDefaultBuilder()
.ConfigureServices(ConfigureServices)
...;
}
}
For my datagrid data i used below lines of code in App.xaml.cs & it worked ..
for de it displayed dot and En it displayed comma for 4 digit numbers.
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
Also, there's another way of doing this, assuming that you're using a TextBlock:
<TextBlock Text="{Binding Salary, Mode=TwoWay, StringFormat='{}{0:C}', ConverterCulture='en-IN'}" />
Please bear in mind the single quotes are needed.

Categories

Resources