Results 1 to 1 of 1

Thread: Localization in WPF and C#

  1. #1

    Thread Starter
    Frenzied Member sciguyryan's Avatar
    Join Date
    Sep 2003
    Location
    Wales
    Posts
    1,763

    Localization in WPF and C#

    Introduction:

    So. You want to know how to build a simple localization system in C# and WPF? No problem! That is what this tutorial is for.

    In this tutorial I will describe my favoured method of localization using XmlDataProvider.

    What Do I Need?

    All you need for this are a WPF C# project (though you are welcome to port it to other languages if you want)! That's it. I'm using a .NET 4.0 language for this but you can use others if you wish.

    Step 1 - Your XML File:

    First you need to add a new directory to your project, you can call it whatever you like but I called mine "languages". Next, inside this file you need to add a new item, an XML file. This will hold your language data. Here is a portion of the XML file used for CSIT:

    xml Code:
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <CSIT for="1.*" name="English">
    3.   <!-- Remember. For menu items the character following the underscore (_) character will be set as the menu accelerator key. -->
    4.   <MenuItems>
    5.     <MenuFile Header="_File" />
    6.     <MenuExit Header="E_xit" />
    7.     <MenuTools Header="_Tools" />
    8.     <MenuOptions Header="_Options..." />
    9.     <MenuHelp Header="_Help" />
    10.     <MenuAbout Header="_About..." />
    11.   </MenuItems>
    12. </CSIT>

    Not to bad eh? As you can see - your standard XML file. You can use whatever layout elements you like, you do not have to use the same structure as mine.

    Now. Once you are done setting up your XML file, name it something like en.xml or whatever language code you are using. Be sure to set the build action of this file to "content" and "copy if newer". This is quite important since if you set these these incorrectly the file will not get copies and updated when you build your program.

    Now. The next stage is to link this file into the program so it can be used.

    Stage 2 - Linking the Documents:

    Thankfully XAML provides a nice easy way of representing this kind of link - a binding. Not all things can be easily bound but most things can.

    You will need to add the following code to your App.xaml document - this will make localizing the whole application much simpler. The code you need is as follows:

    xml Code:
    1. <Application.Resources>
    2.     <XmlDataProvider x:Key="Language" Source="/languages/en.xml" XPath="CSIT"/>
    3. </Application.Resources>

    As you can see. I added mine into the application resources - just to save adding it to each window (since my app has quite a few!).

    A few things to note here, the x:Key represents the ID by which we will access this element later. The source you will need to customize to be the relative location of the XML file to your application.

    Finally, the XPath attribute. You should set this to the root element in your XML document, which in my case was "CSIT".

    So now. You already have the XML document and the basic linking - not bad for a start. But our work is not done yet - now we need to use the information from the XML file in the program via bindings.

    Stage 3 - Data Bindings

    I guess by now, if you have been using WPF and C# you already know about bindings and since this tutorial is about localization I will not dwell on it since there are probably other tutorials on here for that already. Here is an example of how I used the above binding code in my application:

    Code:
    <Menu IsMainMenu="True" Margin="5">
        <MenuItem>
            <MenuItem.Header>
                <AccessText Text="{Binding Source={StaticResource Language}, XPath=MenuItems/MenuFile/@Header}" />
            </MenuItem.Header>
    
            <MenuItem Click="MainWindowExit">
                <MenuItem.Header>
                    <AccessText Text="{Binding Source={StaticResource Language}, XPath=MenuItems/MenuExit/@Header}" />
                </MenuItem.Header>
            </MenuItem>
        </MenuItem>
    </Menu>
    I've bolded the bits that we are interested in. These are binding references. Note that we are using the key for the XmlDataProvider that I described earlier.

    The XPath is what we are interested in here - this is the path, relative to the XPath attribute designed in the main XmlDataProvider element I designed earlier. The item with the at sign (@) prefix represents an attribute which should have its value will be read. So. For the first item above, the resulting menu will show as "File". Simple eh?

    Stage 4 - The Language Framework

    So. We now have a language binding that works - but it's not quite there yet since we can't change languages and without that what good is a localization framework?

    For this next part we will need more code - and luckily I already have the code for it written. The code is attached.

    This code handles most of the work for you. If you do not want the language version compatibility code, feel free to remove it however I found it useful when working with varying program versions.

    In App.xaml.cs add the following code:

    csharp Code:
    1. /// <summary>
    2. /// This will handle the languages and language changes.
    3. /// </summary>
    4. public static LanguageHandler LanguageHandler = new LanguageHandler();

    ... and this will handle the language changes over the whole program. In the starting windows initialization function I added the following code:

    csharp Code:
    1. // Add a language changed listner.
    2. App.LanguageHandler.LanguageChanged += new LanguageHandler.LanguageUpdatedHandler(UpdateLanguage);
    3.  
    4. // Set the language to the default - English.
    5. try
    6. {
    7.     App.LanguageHandler.SetLanguageResource("en");
    8. }
    9. catch (Exception ex)
    10. {
    11.     System.Windows.MessageBox.Show("Language resource could not be set!");
    12.     return;
    13. }

    Strictly speaking I didn't need to call this here given what I have shown you so far - however there are reasons that I will explain below.

    In some occasions there may be items where you have strings that cannot be bound to directly - this is the reason for the event handler. The event handler fires when the language changes and causes a function to be run - in this case the following code:

    csharp Code:
    1. /// <summary>
    2. /// This will cause the special localizable strings to be updated. Those that cannot be directly bound
    3. /// with data bindings.
    4. /// </summary>
    5. private void UpdateLanguage(object sender, LanguageUpdatedArgs e)
    6. {
    7.     this.statusBarStatus.Content = App.LanguageHandler.GetLocalizedString("StatusWelcomeString");
    8. }

    So. This can be used for any items that need to be set dynamically when the changes are made. In my application for example strings need to be checked and changed at varying places.

    Just remember that if you are doing to use the language handler file I included, you will also need to change this line:

    Code:
    strings = languageInfoFile.Element("CSIT").Element("Strings").Elements("String");
    ...And include the new root element in there too or else it will not work!

    Hopefully that will provide a nice introduction to localization - or at least my method of it. If anyone has any comments, suggestions or improvements feel free to share them!

    Thanks for reading.
    Attached Files Attached Files
    My Blog.

    Ryan Jones.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width