implement different language into UWP application from code behind using multilingual - c#

Is it possible to implement different language into UWP application from code behind using multilingual toolkit & not by setting the desired language from the settings but instead from the dropdown list of language within the application

You don't actually need the Multilingual App Toolkit to modify the language of your app. By default, the app will configure itself based on the settings on the machine, but you can override that by setting the CurrentCulture and/or CurrentUICulture.
Say for instance you had a Combobox that contained "English", "Spanish" and "French"... and your desired behavior is to switch your language to whichever value the user selects. All you'd need to do is hook up the SelectionChanged event. Here's what the code might look like:
private void ChangeLanguage(object sender, SelectionChangedEventArgs e)
{
var newlySelected = e.AddedItems[0] as ComboBoxItem;
string newLanguage = newlySelected.Content.ToString();
switch (newLanguage)
{
case "English":
{
CultureInfo.CurrentCulture = new CultureInfo("en");
CultureInfo.CurrentUICulture = new CultureInfo("en");
break;
}
case "Spanish":
{
CultureInfo.CurrentCulture = new CultureInfo("es");
CultureInfo.CurrentUICulture = new CultureInfo("es");
break;
}
case "French":
{
CultureInfo.CurrentCulture = new CultureInfo("fr");
CultureInfo.CurrentUICulture = new CultureInfo("fr");
break;
}
default:
{
throw new NotImplementedException("Unidentified Language");
}
}
}
Naturally, I'd encourage you to do all the appropriate error checking (Make sure that the cast to ComboBoxItem works, etc...).
Also, remember that you need to set CurrentCulture if you want things like Dates and Times to show in the appropriate locale and use CurrentUICulture if you want to modify which resources your ResourceLoader uses to populate the UI.
Hopefully this should get you up and running!
--Dante

Related

Set page culture through DropDown Menu and additionally by Query Parameter

I have a DropDown Menu "DDLanguage" where the user choses the Language for the application, and this ovveride methode thats sets the according Culture. So far so good.
protected override void InitializeCulture()
{
String language = Request.Form["DDLanguage"];
if (!string.IsNullOrEmpty(language))
{
if (language == "auto")
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(HttpContext.Current.Request.UserLanguages[0].Trim());
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(HttpContext.Current.Request.UserLanguages[0].Trim());
}
else
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
}
}
}
I then introduced a Querystring Parameter to pass the selected Language to the page on one of the required reload events. This causes some conflict between the language being given by the query string on one side and the dropdown on the other. I want the Querystring to be mandatory only for the first pageload, but afterwards it should not be considered anymore, as it is then overruled by the choice of the DropDown Menu.
The code I wrote to handle this was:
String language = Request.Form["DDLanguage"];
String languageChanged = Request.Form["LabelLanguage"];
if (!string.IsNullOrEmpty(Request.QueryString["Lang"]) && string.IsNullOrEmpty(languageChanged))
{
language = Request.QueryString["Lang"];
}
where LabelLanguage stores the selection of the DropDown Menu and is empty until a first choice is made.
Unfortunately that doesn't work and the culture is only set by the query Parameter. Any suggestion is appeciated. Thanks, Martin
The logic that I applied was correct, but
String languageChanged = Request.Form["LabelLanguage"];
would not return a value. I now know that I can't process data of a Label, as it is not rendered to a html element containing a value. Instead I use a asp:HiddenField that is rendered in a way its value can be requested by that command.

Refresh all String Resources when Culture Changed

I've written a WPF app in which user can change culture. The Method in app.xaml.cs looks like this :
public void SelectCulture(string culture)
{
// List all our resources
List<ResourceDictionary> dictionaryList = new List<ResourceDictionary>();
foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
{
dictionaryList.Add(dictionary);
}
// We want our specific culture
string requestedCulture = string.Format("Resources/StringResources.{0}.xaml", culture);
ResourceDictionary resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString == requestedCulture);
if (resourceDictionary == null)
{
// If not found, we select our default language
//
requestedCulture = "Resources/StringResources.en-ES.xaml";
resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString == requestedCulture);
}
// If we have the requested resource, remove it from the list and place at the end.\
// Then this language will be our string table to use.
if (resourceDictionary != null)
{
Application.Current.Resources.MergedDictionaries.Remove(resourceDictionary);
Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
}
// Inform the threads of the new culture
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
}
This allows to change on runtime every string resources from different resourcedictionnary.
But not every resources: those which are used in xaml via DynamicResource like this :
<GroupBox Header="{DynamicResource RootSettings}" >
are correctly updated.
But those which are used in C# code like in ViewModel like this :
stTestConnection = System.Windows.Application.Current.Resources["Connectionsucceded"].ToString();
do not update.
All string Resources are declared in different resources dictionaries like this :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- #region Global -->
<system:String x:Key="CriticalErrorTitle">Critical Error</system:String>
<system:String x:Key="ErrorTitle">Error</system:String>
<system:String x:Key="CloseApp">Application will close</system:String>
Any idea why the string resources used in C# are not updating but the ones used in XAML are ?
Ask me if more info needed.
Thanks
I had to do something similar recently with a runtime theme change performing a colour change using Xamarin in c#.
If I remember correctly then in Xaml with DynaminResource they updated automatically. But when in came to the c# code I had to do so manually. This was triggered by a xamarin OnThemeChanged.
If you have access to a similar method during culture change, you could put all your update logic there.

Could a switch statement that switches resources be more generic?

I am working on a kiosk application that has a button to choose a language.
The button after that has a picture of the languages flag and it's name. Right now I am using a switch statement to set the image, but I would like to have it more generic so when adding languages I wouldn't have to change code everywhere. I am getting the image from my apps resources, and I would like to keep it that way.
The only way I can think of would be by retrieving the images from files and naming them according to the language string they are for. The language string is in this format "en-US". Also the language string is declared in a function before this one is called.
private void SetLanguageButton()
{
switch (language)
{
case "en-US":
buttonLanguage.Image = Properties.Resources.en_US;
break;
case "hu-HU":
buttonLanguage.Image = Properties.Resources.hu_HU;
break;
case "sk-SK":
buttonLanguage.Image = Properties.Resources.sk_SK;
break;
}
buttonLanguage.Text = resourceManager.GetString("languageName", cultureInfo);
}
If you have cultural-ized resources, you can get data as following
buttonLanguage.Image =
(Icon)Properties.Resources.ResourceManager.GetObject("langicon", cultureInfo);
buttonLanguage.Text =
Properties.Resources.ResourceManager.GetString("langname", cultureInfo);

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");

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