7

I'm working with VS 2015 on a WPF-test application for a new project in which the user can change the language at runtime.

So i made my testproject according to this article.

I added three RESX-files to the Proerties-folder.

enter image description here

Then i added a constructor and methods for switching between the languages.

namespace MultipleLanguages
{
    /// <summary>
    /// Interaktionslogik für "App.xaml"
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// The constructor.
        /// </summary>
        public App()
        {
            // Sets the desired language.
            ChangeLanguage("de-DE");
        }

        /// <summary>
        /// Switches to language german.
        /// </summary>
        public void SwitchToLanguageGerman()
        {
            ChangeLanguage("de-DE");
        }

        /// <summary>
        /// Switches to language english.
        /// </summary>
        public void SwitchToLanguageEnglish()
        {
            ChangeLanguage("en-US");
        }

        /// <summary>
        /// Changes the language according to the given culture.
        /// </summary>
        /// <param name="culture">The culture.</param>
        private void ChangeLanguage(string culture)
        {
            System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
            System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
            MultipleLanguages.Properties.Resources.Culture = new CultureInfo(culture);
        }

    }
}

Finally i implemented the resources to my WPF window.

First the XAML:

<Window x:Class="MultipleLanguages.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MultipleLanguages"
        xmlns:mlres="clr-namespace:MultipleLanguages.Properties"
        mc:Ignorable="d"
        Title="{x:Static mlres:Resources.mainwindowtitle}"
        Height="350"
        Width="525">

    <Grid x:Name="grd_mainpanel">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Grid x:Name="grd_persondatapanel"
              Grid.Row="0"
              Grid.Column="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0"
                   Grid.Column="0"
                   Content="{x:Static mlres:Resources.firstname}"
                   Margin="5"></Label>

            <Label Grid.Row="1"
                   Grid.Column="0"
                   Content="{x:Static mlres:Resources.lastname}"
                   Margin="5"></Label>
        </Grid>

        <WrapPanel x:Name="wrp_buttonpanel"
                   Grid.Row="1"
                   Grid.Column="0">
            <!--Test to get values from the resources-->
            <Button x:Name="btn_testresource"
                    Margin="5"
                    Click="btn_testresource_Click">Test</Button>
            <!--Switch to language german-->
            <Button x:Name="btn_switchtogerman"
                    Margin="5"
                    Click="btn_switchtogerman_Click"
                    Content="{x:Static mlres:Resources.switchtogerman}"></Button>
            <!--Switch to language english-->
            <Button x:Name="btn_switchtoenglish"
                    Margin="5"
                    Click="btn_switchtoenglish_Click"
                    Content="{x:Static mlres:Resources.switchtoenglish}"></Button>
        </WrapPanel>
    </Grid>

</Window>

And the C#-code:

public partial class MainWindow : Window
{
    /// <summary>
    /// The constructor.
    /// </summary>
    public MainWindow()
    {
        InitializeComponent();
    }

    /// <summary>
    /// For testing the resource dictionaries.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btn_testresource_Click(object sender, RoutedEventArgs e)
    {
        // Shows the name of the current culture.
        System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;
        MessageBox.Show("The name of the current culture is '" + ci.Name + "'");

        ////// Shows the text to the resource key "firstname" according to the current culture.
        ////ResourceManager rm1 = new ResourceManager("MultipleLanguages.TextResource1", System.Reflection.Assembly.GetExecutingAssembly());
        ////MessageBox.Show("'firstname' aus MultipleLanguages.TextResource1" + rm1.GetString("firstname"));
        ////ResourceManager rm2 = new ResourceManager("MultipleLanguages.TextResources.TextResource2", System.Reflection.Assembly.GetExecutingAssembly());
        ////MessageBox.Show("'firstname' aus MultipleLanguages.TextResources.TextResource2" + rm2.GetString("firstname"));

        // Shows values to the given names from the resource - according to the current culture, which was set in App.xaml.cs.
        ResourceManager rm = MultipleLanguages.Properties.Resources.ResourceManager;
        MessageBox.Show("firstname : " + rm.GetString("firstname"));
        MessageBox.Show("lastname : " + rm.GetString("lastname"));
    }

    private void btn_switchtogerman_Click(object sender, RoutedEventArgs e)
    {
        ((App)Application.Current).SwitchToLanguageGerman();
        UpdateLayout();
    }

    private void btn_switchtoenglish_Click(object sender, RoutedEventArgs e)
    {
        ((App)Application.Current).SwitchToLanguageEnglish();
        UpdateLayout();
    }

}

After the start the default language is german.

When i switch then to english the current culture of the thread is changed, but i don't see any change in the GUI.

But when i click the button "Test" i'm getting the english values from the resources.

Finally i tried to refresh the window with UpdateLayout but nothing happened.

Big question: How can i refresh the window at runtime?

P.S.: By using XAML instead of RESX this was no problem (except error messages from validation).

Community
  • 1
  • 1
Patrick Pirzer
  • 1,649
  • 3
  • 22
  • 49
  • Did you already have a look on [this](http://stackoverflow.com/a/4627042/4610605) ? – Felix D. Feb 02 '17 at 11:46
  • Thanks for the hint. By using XAML-resources this was (almost) no problem. But with RESX it is a problem and all recommend RESX. I will make a try with the solution of Tomer. – Patrick Pirzer Feb 02 '17 at 12:32
  • [This](http://stackoverflow.com/questions/3854677/wpf-localization-in-xaml-what-is-the-simple-easy-and-elegant-way-of-doing-it) could also help. Since you're working with wpf this should work. I always use this approach when designing UI and need support for multiple languages. – Felix D. Feb 02 '17 at 12:42
  • The get some help with the `resx` files I use `ResXManager` from the Visual Studio `Extensions and Updates` (MenustripItem 'Tools') – Felix D. Feb 02 '17 at 12:44
  • Hello Felix. Thanks once again for the hint with the WPF localization-project. I implemented it successfully into my testproject and you can view it here: github.com/patrickpirzer/MultipleLanguages – Patrick Pirzer Feb 02 '17 at 15:21

1 Answers1

0

I would suggest using ResourceDictionaries instead of .resx files. On Binding just use DynamicResource. And when you load another ResourceDictionary the text will automatically update. Just follow these steps:

//  On app start load some language dictionary (German in this case)

    Uri uri = new Uri("Resources/German.xaml", UriKind.Relative);
    StreamResourceInfo info = Application.GetContentStream(uri);
    System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
    ResourceDictionary myResourceDictionary = 
                                   (ResourceDictionary)reader.LoadAsync(info.Stream);
    Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary); 

...

    //Now switch to another language (English in this case) on some button click or similar... 

    Application.Current.Resources.MergedDictionaries.Clear();
    Uri uri = new Uri("Resources/English.xaml", UriKind.Relative);
    StreamResourceInfo info = Application.GetContentStream(uri);
    System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
    ResourceDictionary myResourceDictionary = 
                                   (ResourceDictionary)reader.LoadAsync(info.Stream);
    Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary);


...

Your texts shall be bound like this:

                            <TextBlock
                            Text="{DynamicResource myResourceText}" /> 

Content of you English.xml ResourceDictionary shall look like this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <sys:String x:Key="myStringNr1">Start</sys:String>
  <sys:String x:Key="myStringNr2">Stop</sys:String>
</ResourceDictionary>

And your German.xml ResourceDictionary could look like this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <sys:String x:Key="myStringNr1">Starten</sys:String>
  <sys:String x:Key="myStringNr2">Stoppen</sys:String>
</ResourceDictionary>

If your Dictionaries are located in another assembly than locate them like this:

var myDictionary= new Uri("pack://sourceassembly:,,,/resources/English.xaml", UriKind.RelativeOrAbsolute);
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = myDictionary});

Shall you have questions to this approach feel free to leave the comment and I will try to expand my answer. Best regards.

A. Dzebo
  • 558
  • 6
  • 13