views:

532

answers:

4

I've been working on a pet project on the weekends to learn more about C# and have encountered an odd problem when working with localization. To be more specific, the problem I have is with System.Threading.Thread.CurrentThread.CurrentUICulture.

I've set up my app so that the user can quickly change the language of the app by clicking a menu item. The menu item in turn, saves the two-letter code for the language (e.g. "en", "fr", etc.) in a user setting called 'Language' and then restarts the application.

Properties.Settings.Default.Language = "en";
Properties.Settings.Default.Save();
Application.Restart();

When the application is started up, the first line of code in the Form's constructor (even before InitializeComponent()) fetches the Language string from the settings and sets the CurrentUICulture like so:

public Form1()
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo(Properties.Settings.Default.Language);
    InitializeComponent();
}

The thing is, this doesn't work consistently. Sometimes, all works well and the application loads the correct language based on the string saved in the settings file. Other times, it doesn't, and the language remains the same after the application is restarted.

At first I thought that I didn't save the language before restarting the application but that is definitely not the case. When the correct language fails to load, if I were to close the application and run it again, the correct language would come up correctly. So this implies that the Language string has been saved but the CurrentUICulture assignment in my form constructor is having no effect sometimes.

Any help? Is there something I'm missing of how threading works in C#? This could be machine-specific, so if it makes any difference I'm using Pentium Dual-Core CPU.

UPDATE

Vlad asked me to check what the CurrentThread's CurrentUICulture is. So I added a MessageBox on my constructor to tell me what the CurrentUICulture two-letter code is as well as the value of my Language user string.

MessageBox.Show(string.Format("Current Language: {0}\nCurrent UI Culture: {1}", Properties.Settings.Default.Language, Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName));

When the wrong language is loaded, both the Language string and CurrentUICulture have the wrong language. So I guess the CurrentUICulture has been cleared and my problem is actually with the Language Setting.

So I guess the problem is that my application sometimes loads the previously saved language string rather than the last saved language string. If the app is restarted, it will then load the actual saved language string.

+1  A: 

Could you check what is your thread's CurrentUICulture?

I remember having a problem like yours; it was solved by reloading the resource dictionary containing the strings to be localized:

Thread.CurrentThread.CurrentUICulture = <new culture>;
ResourceDictionary newDict = new ResourceDictionary();
newDict.Source = localizedStrings.Source;
localizedStrings = newDict;

(and this approach worked dynamically as well; here is some more information).

Vlad
Good question, it seems I was wrong to say the problem lies with the CurrentThread. I've updated my post but apparently the problem lies with the call the Properties.Settings.Default.Language. It seems to be loading the old language rather than the langauge that has been last saved. After restarting for a second time, the language that has been last saved is actually loaded.P.S. Tried to upvote you but alas, not enough rep.
xTRUMANx
A: 

You could simply "reset" your application by closing the open forms and re-creating them. Then you could directly set the culture when the user changes the setting.

Also, try giving some debug output so you see what values are being set and if the culture is actually what you expect.

EDIT: My guess: Since the data has to be written to a file, and then loaded from that file, you may be restarting too quickly for the write to have been completed.

Daniel Rose
I've updated my post as I've found out the actual problem isn't with the CurrentThread.CurrentUICulture assignment but the call to my Language setting.However, I'm not quite sure I understand your 'reset' suggestion. There may be a lot of different types of Forms open when the user changes the language. Recreating them wouldn't be easy as I wouldn't know which forms were open, what parameters their constructors would need, etc.
xTRUMANx
By reset I meant finding all your open windows, closing them, and then opening the main form. However, personally I would prefer if you would show a message along the lines of "Language change will not go into effect until application is restarted." That way, the user won't lose any open work.
Daniel Rose
A: 

Hi, I got the same problem. I figured out that Application.Restart() do not really make an absolutely restart, see: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.restart.aspx

So Application.Restart() do not call the initializing things within the forms constructer like InitializeComponent(), more the "Applications are restarted in the context in which they were initially run."

So You code is correct Properties.Settings.Default.Language = "en"; Properties.Settings.Default.Save(); and public Form1() { Thread.CurrentThread.CurrentUICulture = new CultureInfo(Properties.Settings.Default.Language); //... InitializeComponent(); } but it doesnt work this way with Application.Restart(). If You close the app and open it again your (new) settings are taken.

So we have find a way to initialize the form again to make new language settings happen.

Harald
A: 

By using CurrentThread.CurrentUICulture, and then changing the form, you don't need to restart the application. Ref my old post here

bna