How do I change localization in C# on Windows Phone? - c#

I have my Resource files with 2 languages and my app already reads the values of one of them. I would like to be able to change the language of my app (use the other resource file) in C# instead of changing the language of the whole phone in Settings.
Is this possible? If so, how?

In App.xaml.cs, in the InitializePhoneApplication method:
private void InitializePhoneApplication()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
.......
}
The limitation is that it needs to be in the app initialization, so if the user changes the language, a restart will be required for it to take effect.

you can do this without need to restart by reloading the page where the user change a language and maintaining the RTL/LTR of your page layout
I added this function in App.xaml.cs
public static void ChangeAppLanguage(string CultureName)
{
App.RootFrame.Language = XmlLanguage.GetLanguage(CultureName);
FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
App.RootFrame.FlowDirection = flow;
App.Current.RootVisual.UpdateLayout();
App.RootFrame.UpdateLayout();
var ReloadUri =( App.RootFrame.Content as PhoneApplicationPage).NavigationService.CurrentSource;
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri(ReloadUri + "?no-cache=" + Guid.NewGuid(), UriKind.Relative));
}
where the CultureName like this : "ar-SA", "en-US"
and I called like this
private void EnglishMenuItem_Click(object sender, EventArgs e)
{
try
{
if(Thread.CurrentThread.CurrentCulture.Name == "en-US")
Thread.CurrentThread.CurrentCulture = new CultureInfo("ar-SA");
else
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
AppResources.Culture = Thread.CurrentThread.CurrentCulture;
App.ChangeAppLanguage(Thread.CurrentThread.CurrentCulture.Name);
//this._contentLoaded = false; //this way does not refresh appBar
//this.InitializeComponent();
//this way work for one time only => if user change language more thane once the api does NOT call constructor
//NavigationService.Navigate(new System.Uri("/PhoneApp2;component/MainPage.xaml", System.UriKind.Relative));
}
catch (Exception ex)
{
MessageBox.Show("error:\n\n" + ex.Message);
}
}

Related

Localized WinForm, load Resources.lang-LANG.resx at runtime? [duplicate]

I want to change Language but when I compile this an exception pop up. it says
"Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure "System.Type.resources" was correctly
embedded or linked into assembly "mscorlib" at compile time, or that
all the satellite assemblies required are loadable and fully signed."
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem.ToString() == "English")
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("En");
ChangeLanguage("En");
}
else if (comboBox1.SelectedItem.ToString() == "German")
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("De");
ChangeLanguage("De");
}
}
private void ChangeLanguage(string lang)
{
foreach (Control c in this.Controls)
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(Type));
resources.ApplyResources(c, c.Name, new CultureInfo(lang));
}
}
Any suggestions?
ComponentResourceManager resources = new ComponentResourceManager(typeof(Type));
The argument to the constructor is wrong, you are telling it to find the resources for System.Type. Which is why it is complaining that it can't find "System.Type.resources". It will never find those.
You need to pass the type of the form that you actually want to localize. Use this.GetType() instead. Albeit that this probably will just localize your Options form and not the rest of the windows in your app. You could iterate Application.OpenForms() instead. It is also necessary to apply the localization to all the controls. Not just the ones on the form, also the ones that are located inside containers like panels. Thus:
private static void ChangeLanguage(string lang) {
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
foreach (Form frm in Application.OpenForms) {
localizeForm(frm);
}
}
private static void localizeForm(Form frm) {
var manager = new ComponentResourceManager(frm.GetType());
manager.ApplyResources(frm, "$this");
applyResources(manager, frm.Controls);
}
private static void applyResources(ComponentResourceManager manager, Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
manager.ApplyResources(ctl, ctl.Name);
applyResources(manager, ctl.Controls);
}
}
Be careful with wiz-bang features like this. Nobody actually changes their native language while they are using your program.
private void ChangeLanguage(CultureInfo culture)
{
Application.CurrentCulture = culture;
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture.Name);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(culture.Name);
}
You'll need to have appropriate resources for all languages though.

Multiple actions on one Button

In a WinForms (C#) application, I have created a language menu strip and a sound button but I don't know how to make them switchable.
I mean I want the sound button to stop sound when i hit it & play sound when i hit it again and change its icon as well ?
Similarly, the language menu, how to make it change language with "Localizable" and its text to the other language at first hit, then turn back at second hit ?
Here is my code:
using System.Globalization;
using System.Threading;
namespace Project
{
public partial class Form2 : Form
{}
private void Menu_LanguageSwitch_Click (object sender, EventArgs e)
{
//Switch to EN - what's here?
{
CultureInfo ci = new CultureInfo("en-US");
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
System.ComponentModel.ComponentResourceManager res = new ComponentResourceManager(typeof(Form2));
res.ApplyResources(lbl_Status, "lbl_Status");
Menu_LanguageSwitch.Text = "Francais";
}
//Switch to French
{
CultureInfo ci = new CultureInfo("fr");
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
System.ComponentModel.ComponentResourceManager res = new ComponentResourceManager(typeof(Form2));
res.ApplyResources(Menu_LanguageSwitch, "Menu_LanguageSwitch");
res.ApplyResources(label2, "label2");
res.ApplyResources(label3, "label3");
res.ApplyResources(label4, "label4");
res.ApplyResources(label5, "label5");
res.ApplyResources(label6, "label6");
res.ApplyResources(label7, "label7");
res.ApplyResources(label8, "label8");
res.ApplyResources(lbl_Status, "lbl_Status");
Menu_LanguageSwitch.Text = "Francais";
}
}
}
Thank you, please make it clear to a beginner. I'ma "rookie".
You'll need to keep track of the current state of the program, so you can check against it when the button is pushed. For simple flags (like "Mute") this can just be a bool:
private bool isMuted = false;
private void onSoundClick(...)
{
if (isMuted)
{
//Do unmute kind of things
isMuted = false;
}
else
{
//Do mute kind of things
isMuted = true;
}
}
The localization logic would be similar, but if you want it to be more than 2 languages, you'll need to cycle through a list/queue.
the simple way is the use a form scope variable
Externalize to the form
CultureInfo ci = new CultureInfo("fr");
when you click the button check the active CutureInfo and then switch to the correct

Change App language at RunTime on-the-fly

I'm currently developing a metro app in which the user can change current language at runtime and all the custom controls that are loaded must update their text regarding to the new language. Problem is that when I change the language using the following code, the app language changes but it will only update text when I restart my app because the pages and controls that are already rendered are cached.
LocalizationManager.UICulture = new System.Globalization.CultureInfo((string)((ComboBoxItem)e.AddedItems[0]).Tag);
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = ((ComboBoxItem)e.AddedItems[0]).Tag as String;
What should I do to force updating text of all custom controls at runtime without restarting my app?
Use this:
var NewLanguage = (string)((ComboBoxItem)e.AddedItems[0]).Tag;
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = NewLanguage;
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForViewIndependentUse().Reset();
//Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset();
Windows.ApplicationModel.Resources.Core.ResourceManager.Current.DefaultContext.Reset();
and then reload your Page, using Navigate method:
if (Frame != null)
Frame.Navigate(typeof(MyPage));
In order to respond right away, you would need to reset the context of the resource manager.
For Windows 8.1:
var resourceContext = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView();
resourceContext.Reset();
You will still need to force your page to redraw itself and thus re-request the resources to get the changes to take place. For Windows 8, you can see https://timheuer.com/blog/archive/2013/03/26/howto-refresh-languages-winrt-xaml-windows-store.aspx
You can change the app's language at runtime with the help of this source code. I took help from this and manipulated my app's language settings page as follows:
In languageSettings.xaml.cs:
public partial class LanguageSettings : PhoneApplicationPage
{
public LanguageSettings()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (ChangeLanguageCombo.Items.Count == 0)
{ ChangeLanguageCombo.Items.Add(LocalizationManager.SupportedLanguages.En);
ChangeLanguageCombo.Items.Add(LocalizationManager.SupportedLanguages.Bn);
}
SelectChoice();
}
private void ButtonSaveLang_OnClick(object sender, RoutedEventArgs e)
{
//Store the Messagebox result in result variable
MessageBoxResult result = MessageBox.Show("App language will be changed. Do you want to continue?", "Apply Changes", MessageBoxButton.OKCancel);
//check if user clicked on ok
if (result == MessageBoxResult.OK)
{
var languageComboBox = ChangeLanguageCombo.SelectedItem;
LocalizationManager.ChangeAppLanguage(languageComboBox.ToString());
//Application.Current.Terminate(); I am commenting out because I don't neede to restart my app anymore.
}
else
{
SelectChoice();
}
}
private void SelectChoice()
{
//Select the saved language
string lang = LocalizationManager.GetCurrentAppLang();
if(lang == "bn-BD")
ChangeLanguageCombo.SelectedItem = ChangeLanguageCombo.Items[1];
else
{
ChangeLanguageCombo.SelectedItem = ChangeLanguageCombo.Items[0];
}
}
}
***Note: Before understanding what I did on LanguageSettings page's code behind, you must implement the codes from the link as stated earlier. And also it may be noted that I am working on windows phone 8

Proper way to change language at runtime

What is the proper way to change Form language at runtime?
Setting all controls manually using recursion like this
Save language choice to file > Restart Application > Load languge
choice before InitializeComponent();
Using Form constructor to replace instance of active from (if this is even possible)
Something else
There is so much half written threads about this but none provides real answer on what is proper way to do this?
UPDATE:
To clarify my question:
Doing something like this:
public Form1()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
this.InitializeComponent();
}
works fine and all my controls and everything else in resources get translated correctly.
And doing something like:
private void button1_Click(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
}
does nothing, Form stays in language I set up before InitializeComponent();
I believe the solution shown in Hans Passant's comment might be the only (general) solution.
Personally, I use this base class for all forms that need to be localized:
public class LocalizedForm : Form
{
/// <summary>
/// Occurs when current UI culture is changed
/// </summary>
[Browsable(true)]
[Description("Occurs when current UI culture is changed")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Category("Property Changed")]
public event EventHandler CultureChanged;
protected CultureInfo culture;
protected ComponentResourceManager resManager;
/// <summary>
/// Current culture of this form
/// </summary>
[Browsable(false)]
[Description("Current culture of this form")]
[EditorBrowsable(EditorBrowsableState.Never)]
public CultureInfo Culture
{
get { return this.culture; }
set
{
if (this.culture != value)
{
this.ApplyResources(this, value);
this.culture = value;
this.OnCultureChanged();
}
}
}
public LocalizedForm()
{
this.resManager = new ComponentResourceManager(this.GetType());
this.culture = CultureInfo.CurrentUICulture;
}
private void ApplyResources(Control parent, CultureInfo culture)
{
this.resManager.ApplyResources(parent, parent.Name, culture);
foreach (Control ctl in parent.Controls)
{
this.ApplyResources(ctl, culture);
}
}
protected void OnCultureChanged()
{
var temp = this.CultureChanged;
if (temp != null)
temp(this, EventArgs.Empty);
}
}
Then instead of directly changing Thread.CurrentThread.CurrentUICulture, I use this property in static manager class to change UI culture:
public static CultureInfo GlobalUICulture
{
get { return Thread.CurrentThread.CurrentUICulture; }
set
{
if (GlobalUICulture.Equals(value) == false)
{
foreach (var form in Application.OpenForms.OfType<LocalizedForm>())
{
form.Culture = value;
}
Thread.CurrentThread.CurrentUICulture = value;
}
}
}
I have found another way:
Move initialization form code in a private method like below:
private void FormInitialize() {/*Your code here*/}
In the form constructor use it like this:
public Form1()
{
InitializeComponent();
FormInitialize();
}
And from Button, menuItem or other call method like this:
private void ChangeCultureToFrench_Click(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr");
this.Controls.Clear();
this.InitializeComponent();
FormInitialize();
}
I hope this helps ;-)
I've discovered this kind of approach a few minutes ago. Just quick and simple restart of the main form. Meybe it will help to someone. Event is created inside the form on my own, called when user selects the language from menu but after the selected culture's name is saved into the settings. Culture names are then loaded from that settings. Works exactly as I need and looks like proper solution.
static class Program
{
private static bool doNotExit = true;
private static FormMain fm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
while(doNotExit)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(Properties.Settings.Default.language);//
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(Properties.Settings.Default.language);//
doNotExit = false;
fm = new FormMain();
fm.lanugageChangedEvent += new EventHandler(main_LanugageChangedEvent);
Application.Run(fm);
}
}
static void main_LanugageChangedEvent(object sender, EventArgs e)
{
doNotExit = true;
fm.Close();
}
}
In reference to your ColumnHeader .NET framework bug, I also discovered this bug recently and posted a question about it (to which I haven't received any responses). I was able to fix the problem by hardcoding the changes for the ColumnHeaders. For example:
resources.ApplyResources(_myHeader, "_myHeader", culture);
You basically just replace the call to .Name with a literal string of the name. I have tested this and it works. Unfortunately this means it won't fit as part of the code you use to change all of the controls. You will have to add a line for each ColumnHeader object you need to change. If you have a listview with a variable number of columns, that could get tricky. Another option is to create localized resource files. I assume you probably already have them for stuff like message box text and other strings. Then you can add an entry in your resource file like "columnHeader_myHeader" and set the appropriate language text for each language. Finally, you can manually change the text to your column headers by using:
_myHeader.Text = myResourceFileName.columnHeader_myHeader;
This will select the appropriate language based on the current thread culture.
Hans was correct in that there doesn't seem to be a foolproof "proper" way to perform localization in .NET, though there are a variety of tools you can use. For something like a job application, even though it is probably already too late for this advice, my suggestion would be to learn as many different methods as you can for localization, learn the pros and cons, and then just pick a system and be able to argue why you believe it is the "proper" choice. They are probably more concerned with your logic and reasoning and demonstration of prior experience than they are with the actual method.
Hope this would help anyone, I found it best for me cause i needed to change buttons location according the lang (browse on the right or left of the search box and labels next to text fields).
save a public var on the main that will hold the lang.
created a class which handles the visual part
created xml files that will hold any language data and more (in my xml tag name=object name).
sent that class's constructor the form (to save and work with)
connect to that current xml file
From main form call whenever you want to initialView (part of the view class) and change lang (and more) anytime (just connect to the right xml file):
public void initialView()
{
//Set rightToLeft values
initialIndent(mainForm);
//set visual text values
initialTxt();
}
private void initialTxt()
{
// Are there any more controls under mainObj (Form1)?
Boolean endOfElemsUnderPnl = false;
// The current Control im working on
Object curObj = mainForm;
do
{
// MenuStrip needs to be handled separately
if (typeof(MenuStrip).ToString().Equals(curObj.GetType().ToString()))
{
foreach (ToolStripMenuItem miBase in ((MenuStrip)(curObj)).Items)
{
miBase.Text = mainForm.dbCon.getData(miBase.Name.ToString());
foreach (ToolStripMenuItem miInnerNode in miBase.DropDownItems)
{
miInnerNode.Text = mainForm.dbCon.getData(miInnerNode.Name.ToString());
}
}
}
// Any other Control i have on the form
else
{
((Control)(curObj)).Text = mainForm.dbCon.getData(((Control)(curObj)).Name.ToString());
}
curObj = mainForm.GetNextControl(((Control)(curObj)), true);
// Are there any more controls under mainObj?
if (null == curObj)
{
endOfElemsUnderPnl = true;
}
} while (!endOfElemsUnderPnl);
}
private void initialIndent(frmMyFileManager parent)
{
if (parent.Language.Equals("Hebrew"))
{
parent.RightToLeft = RightToLeft.Yes;
}
else if (parent.Language.Equals("English"))
{
parent.RightToLeft = RightToLeft.No;
}
else
{
parent.RightToLeft = RightToLeft.No;
}
}
And this is an example of how easy it is for my at runtime:
private void selectLanguageToolStripMenuItem_Click(object sender, EventArgs e)
{
DialogResult res = MessageBox.Show(this, "click yes for english and no for hebrew", "Select language", MessageBoxButtons.YesNoCancel);
if (DialogResult.Yes == res)
{
Language = "English";
}
else if (DialogResult.No == res)
{
Language = "Hebrew";
}
dbCon = new CDBConnector("****\\lang" + Language + ".xml");
view.initialView();
}

problem :globalization in C# using VS2005

I want to globalize my application.
I have created a small form which asks the user their language.
I have a number of problems :
Problem 1:
In program.cs
new SplashScreen(_tempAL);
new LangForm(_lang);
Application.Run(new Form1(_tempAL, _lang));
I want the application not to call Form1 until the user clicks on OK in LangForm .
For more explaintion in LangForm :
public LangForm(char _langChar)
{
InitializeComponent();
_ch = _langChar;
this.TopMost = true;
this.Show();
}
private void _btnOk_Click(object sender, EventArgs e)
{
string _langStr = _cbLang.SelectedText;
switch (_langStr)
{
case "English":
_ch = 'E';
this.Hide();
break;
case "Arabic":
_ch = 'A';
this.Hide();
break;
case "Frensh":
_ch ='F';
this.Hide();
break;
}
_pressedOk = true;
}
private void _btnCancel_Click(object sender, EventArgs e)
{
this.Close();
Application.Exit();
}
Now when I debug, the application calls LangForm and then Form1 so both forms are shown.
I want Form1 to wait until the user clicks on Ok in LangForm.
Problem 2:
When should I check on the language? It's not allowed to check in "initializeComponent()"
so should I check after this function and then set controls location according to the language.
Problem 3:
Within application process I displays some message so before each "MessageBox.Show("");" I should check for the language or there is another way where I may set the language once.
Problem 4:
I have searched for interfaces for MessageBox as actually I want to change its layout. How can I find templates for MessageBox?
Thanks in-advance.
Display the language selection form as a dialog. Make your Program.cs file look like this:
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (DialogResult.OK == new LangForm().ShowDialog()) {
Application.Run(new Form1());
}
}
Add this line to your _btnOK click handler:
this.DialogResult = DialogResult.OK;
To block until a form has closed, use .ShowDialog() on the LangForm. I would then set the culture (Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICulture) between this form closing and creating the new form. Having done this, anything from resx should load correctly.
For changing the layout of MsgBox (beyond the norm) you would have to write your own (it doesn't support this).
Something like:
[STAThread]
static void Main() {
Application.EnableVisualStyles();
// find the culture we want to use
bool cont;
string languageCode;
using (LangForm lang = new LangForm()) {
cont = lang.ShowDialog() == DialogResult.OK;
languageCode = lang.LanguageCode; // "en-US", etc
}
if (!cont) return;
// set the culture against the UI thread
Thread.CurrentThread.CurrentCulture =
Thread.CurrentThread.CurrentUICulture =
CultureInfo.GetCultureInfo(languageCode);
// show the main UI
using (MainForm main = new MainForm()) {
Application.Run(main);
}
}
Note the use of the official culture codes will make it easier to use things like CultureInfo; if you want to use your own short-list, then use an enum, and write a method somewhere:
public static string GetCultureCode(MyCulture culture) {
switch(culture) {
case MyCulture.French: return "fr-FR";
case MyCulture.English: return "en-GB";
//...
default: throw new NotSupportedException("Unexpected culture: " + culture);
}
}

Categories

Resources