As a speaker of a foreign language and a former software tester for many localization projects, I have a continued interest in how to globalize and localize my applications. Fortunately, it has gotten much easier through the years as operating systems have become more accommodating to things like DBCS and bidirectional support. .NET has also continued to improve by adding better resource integration support and fortunately Silverlight is no exception in using this functionality.
Unlike with 3.0, Silverlight 4.0 provides a “ResourceWrapper.cs” class by default which encapsulates your resource references and binds the navigation elements out of the box. With only a few extra steps, you can fully globalize an application which will allow you to easily switch between languages on the fly.
Instructions
1. Open Visual Studio and create a “Silverlight Business Application.” (Note: If you are creating any other type of Silverlight application, I recommend seeing Tim Heuer’s blog entry mentioned below.)
2. Update the project file to support multiple languages.
i. Save the application and close Visual Studio.
ii. Open the Silverlight csproj file in notepad.
iii. Add as many culture names as will be supported. (See below for complete list.)
<SupportedCultures>en-US,ja-JP</SupportedCultures>
iv. Reopen the project in Visual Studio.
3. Add additional resource files for each culture name that you support.
i. Under the Assets –> Resources folder, copy and paste the ApplicationStrings.resx file and rename it using the appropriate culture name. For example, ApplicationStrings.ja-jp.resx would be used for Japanese.
ii. Double click on the resx file and ensure that the “No code generated” is picked for the Access Modifier. You can also delete the corresponding code behind file.
ii. Update the resource file with localized strings. In the following example, I have added a resource for Japanese and translated a few items.
iv. VERY IMPORTANT: If you add additional strings to your resource files, you will need to go into the original ApplicationStrings.Designer.cs file and ensure that the constructor is set to “public”. There is a bug in Visual Studio that changes it to “internal”. As of Visual Studio 2010 Beta 2, this is still a problem.
v. Binding is done in xaml with the following example.
Content="{BindingPath=ApplicationStrings.MyNewString, Source={StaticResource ResourceWrapper}}"
4. Update the ResourceWrapper.cs file to implement the INotifyPropertyChanged interface.
using System.ComponentModel;
public sealed classResourceWrapper : INotifyPropertyChanged
{
private staticApplicationStrings applicationStrings = new ApplicationStrings();
private static SecurityQuestions securityQuestions = new SecurityQuestions();
public ApplicationStrings ApplicationStrings
{
get { return applicationStrings; }
set { OnPropertyChanged("ApplicationStrings"); }
}
public SecurityQuestions SecurityQuestions
{
get { return securityQuestions; }
set { OnPropertyChanged("SecurityQuestions"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
5. Add a UI element for changing languages. In this example, I us a ComboBox.
i. Copy and paste the following code in the MainPage.xaml file after the “About” button.
<ComboBox Name="Language" SelectionChanged="Language_SelectionChanged">
<ComboBoxItem Content="English" Tag="en-US" IsSelected="True" />
<ComboBoxItem Content="日本語" Tag="ja-JP" />
</ComboBox>ii. Add the following code behind.
private void Language_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Thread.CurrentThread.CurrentCulture =
new CultureInfo(((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag.ToString());
Thread.CurrentThread.CurrentUICulture =
new CultureInfo(((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag.ToString());
((ResourceWrapper)App.Current.Resources["ResourceWrapper"]).ApplicationStrings =
new ApplicationStrings();
}
Run your application…
References
Tim Heuer - Silverlight and localizing string data - Although Tim’s example is for 3.0, I used it quite liberally in this post. I give Tim full credit for helping me understand how localization works in Silverlight.
Table of Language Culture Names, Codes, and ISO Values Method [C++]
Display Name | Culture Name |
Afrikaans - South Africa | af-ZA |
Albanian - Albania | sq-AL |
Arabic - Algeria | ar-DZ |
Arabic - Bahrain | ar-BH |
Arabic - Egypt | ar-EG |
Arabic - Iraq | ar-IQ |
Arabic - Jordan | ar-JO |
Arabic - Kuwait | ar-KW |
Arabic - Lebanon | ar-LB |
Arabic - Libya | ar-LY |
Arabic - Morocco | ar-MA |
Arabic - Oman | ar-OM |
Arabic - Qatar | ar-QA |
Arabic - Saudi Arabia | ar-SA |
Arabic - Syria | ar-SY |
Arabic - Tunisia | ar-TN |
Arabic - United Arab Emirates | ar-AE |
Arabic - Yemen | ar-YE |
Armenian - Armenia | hy-AM |
Azeri (Cyrillic) - Azerbaijan | Cy-az-AZ |
Azeri (Latin) - Azerbaijan | Lt-az-AZ |
Basque - Basque | eu-ES |
Belarusian - Belarus | be-BY |
Bulgarian - Bulgaria | bg-BG |
Catalan - Catalan | ca-ES |
Chinese - China | zh-CN |
Chinese - Hong Kong SAR | zh-HK |
Chinese - Macau SAR | zh-MO |
Chinese - Singapore | zh-SG |
Chinese - Taiwan | zh-TW |
Chinese (Simplified) | zh-CHS |
Chinese (Traditional) | zh-CHT |
Croatian - Croatia | hr-HR |
Czech - Czech Republic | cs-CZ |
Danish - Denmark | da-DK |
Dhivehi - Maldives | div-MV |
Dutch - Belgium | nl-BE |
Dutch - The Netherlands | nl-NL |
English - Australia | en-AU |
English - Belize | en-BZ |
English - Canada | en-CA |
English - Caribbean | en-CB |
English - Ireland | en-IE |
English - Jamaica | en-JM |
English - New Zealand | en-NZ |
English - Philippines | en-PH |
English - South Africa | en-ZA |
English - Trinidad and Tobago | en-TT |
English - United Kingdom | en-GB |
English - United States | en-US |
English - Zimbabwe | en-ZW |
Estonian - Estonia | et-EE |
Faroese - Faroe Islands | fo-FO |
Farsi - Iran | fa-IR |
Finnish - Finland | fi-FI |
French - Belgium | fr-BE |
French - Canada | fr-CA |
French - France | fr-FR |
French - Luxembourg | fr-LU |
French - Monaco | fr-MC |
French - Switzerland | fr-CH |
Galician - Galician | gl-ES |
Georgian - Georgia | ka-GE |
German - Austria | de-AT |
German - Germany | de-DE |
German - Liechtenstein | de-LI |
German - Luxembourg | de-LU |
German - Switzerland | de-CH |
Greek - Greece | el-GR |
Gujarati - India | gu-IN |
Hebrew - Israel | he-IL |
Hindi - India | hi-IN |
Hungarian - Hungary | hu-HU |
Icelandic - Iceland | is-IS |
Indonesian - Indonesia | id-ID |
Italian - Italy | it-IT |
Italian - Switzerland | it-CH |
Japanese - Japan | ja-JP |
Kannada - India | kn-IN |
Kazakh - Kazakhstan | kk-KZ |
Konkani - India | kok-IN |
Korean - Korea | ko-KR |
Kyrgyz - Kazakhstan | ky-KZ |
Latvian - Latvia | lv-LV |
Lithuanian - Lithuania | lt-LT |
Macedonian (FYROM) | mk-MK |
Malay - Brunei | ms-BN |
Malay - Malaysia | ms-MY |
Marathi - India | mr-IN |
Mongolian - Mongolia | mn-MN |
Norwegian (Bokmål) - Norway | nb-NO |
Norwegian (Nynorsk) - Norway | nn-NO |
Polish - Poland | pl-PL |
Portuguese - Brazil | pt-BR |
Portuguese - Portugal | pt-PT |
Punjabi - India | pa-IN |
Romanian - Romania | ro-RO |
Russian - Russia | ru-RU |
Sanskrit - India | sa-IN |
Serbian (Cyrillic) - Serbia | Cy-sr-SP |
Serbian (Latin) - Serbia | Lt-sr-SP |
Slovak - Slovakia | sk-SK |
Slovenian - Slovenia | sl-SI |
Spanish - Argentina | es-AR |
Spanish - Bolivia | es-BO |
Spanish - Chile | es-CL |
Spanish - Colombia | es-CO |
Spanish - Costa Rica | es-CR |
Spanish - Dominican Republic | es-DO |
Spanish - Ecuador | es-EC |
Spanish - El Salvador | es-SV |
Spanish - Guatemala | es-GT |
Spanish - Honduras | es-HN |
Spanish - Mexico | es-MX |
Spanish - Nicaragua | es-NI |
Spanish - Panama | es-PA |
Spanish - Paraguay | es-PY |
Spanish - Peru | es-PE |
Spanish - Puerto Rico | es-PR |
Spanish - Spain | es-ES |
Spanish - Uruguay | es-UY |
Spanish - Venezuela | es-VE |
Swahili - Kenya | sw-KE |
Swedish - Finland | sv-FI |
Swedish - Sweden | sv-SE |
Syriac - Syria | syr-SY |
Tamil - India | ta-IN |
Tatar - Russia | tt-RU |
Telugu - India | te-IN |
Thai - Thailand | th-TH |
Turkish - Turkey | tr-TR |
Ukrainian - Ukraine | uk-UA |
Urdu - Pakistan | ur-PK |
Uzbek (Cyrillic) - Uzbekistan | Cy-uz-UZ |
Uzbek (Latin) - Uzbekistan | Lt-uz-UZ |
Vietnamese - Vietnam | vi-VN |
Very helpful! Thanks!
ReplyDeleteThanks very much this was very helpful. The only thing I could add is that one needs to add a few reference at the top of MainPage.cs. In particular:
ReplyDeleteSystem.Threading;
System.Globalization;
MyProject.Resources;
Greg 'Hollywood' Gum
Turns out Brad Abrams ended up blogging on this too. If you get stuck, check out his post as well.
ReplyDeletehttp://blogs.msdn.com/brada/archive/2010/03/22/silverlight-4-ria-services-ready-for-business-localizing-business-application.aspx
Hi John:
ReplyDeleteI just made this localization work but in the Brad Abrams link (provided by you) he tries to read the culture from the user browser and it is not working, any ints on this?
Thanks a lot...
I had a similar problem before, but didn't find a resolution. I had changed my OS system locale to another language, but it didn't pick it up. Unfortunately I didn't have access to a fully localized OS at the time either in case that was the issue. Let me know if you find a solution.
ReplyDeleteThanks John, will wait patiently.
ReplyDeleteHello John and thank you for the great tutorial!
ReplyDeleteThe thing that I don't understand and don't know how to do, is when I have to change the text from code behind(c#).
Let's say I have a textblock named txtWelcome. From xaml I'm saying text="Welcome".I have two resx, one for greek and one for english. They both have the txtWelcome parameter inside and each of them has the analogous text. What if I change the txtWelcome from the c# code? I mean will I write txtWelcome.text="WELCOME2" or txtWelcome.text="ΓΕΙΑΣΟΥ2"?
I have some messageboxes also. How could I know which text to put? There are also some textblocks, that don't have their text filled in the beginning. The text is filled from code-behind.
Can you help me please??
Hi there! I suggest trying https://poeditor.com to easily localize your app or other software product. Give it a try and see how it functions, maybe it's an useful localization tool. Cheers!
ReplyDelete