简体   繁体   中英

Localizing Commands and CultureInfo in WPF

Currently, I'm trying to create application which supports language switching at run-time. I've found one tutorial, which suggested using Resource Dictionaries for that purpose. Suggested approach works just fine for elements in XAML, that have their content set, for example, as follows <Button Content="{DynamicResource MainTitle}" .

The thing is that my MenuItem , which has it's Header set to the Text of Command bound to it, doesn't change Header according to CurrentUICulture . It remains the same, or, I should say, correct for project's default language, although I'm changing one with language switching. Same goes for MenuItems representing supported languages.

Here is the code I'm using.

App.xaml.cs

public partial class App : Application
{
    private static String prefix = "Resources/lang.";
    public static event EventHandler LanguageChanged;
    private static List<CultureInfo> m_Languages = new List<CultureInfo>();
    public static List<CultureInfo> Languages
    {
        get
        {
            return m_Languages;
        }
    }
    public static CultureInfo Language
    {
        get
        {
            return System.Threading.Thread.CurrentThread.CurrentUICulture;
        }
        set
        {
            if (value == null) throw new ArgumentNullException("value");
            if (value == System.Threading.Thread.CurrentThread.CurrentUICulture) return;

            System.Threading.Thread.CurrentThread.CurrentUICulture = value;
            ResourceDictionary dictionary = new ResourceDictionary();
            dictionary.Source = new Uri(String.Format(prefix+ "{0}.xaml", value.Name), UriKind.Relative);
            ResourceDictionary oldDictionary = (from d in Current.Resources.MergedDictionaries
                                                where d.Source != null &&
                                                d.Source.OriginalString.StartsWith(prefix)
                                                select d).First();

            if (oldDictionary != null)
            {
                int index = Current.Resources.MergedDictionaries.IndexOf(oldDictionary);
                Current.Resources.MergedDictionaries.Remove(oldDictionary);
                Current.Resources.MergedDictionaries.Insert(index, dictionary);
            }
            else
            {
                Current.Resources.MergedDictionaries.Add(dictionary);
            }
            LanguageChanged(Current, new EventArgs());
        }
    } 
    public App()
    {
        InitializeComponent();
        App.LanguageChanged += App_LanguageChanged;
        m_Languages.Clear();
        m_Languages.Add(new CultureInfo("en"));
        m_Languages.Add(new CultureInfo("ru-RU"));
        Language = WpfTestProject.Properties.Settings.Default.DefaultLanguage;
    }
    public void App_LanguageChanged(Object sender, EventArgs e)
    {
        WpfTestProject.Properties.Settings.Default.DefaultLanguage = Language;
        WpfTestProject.Properties.Settings.Default.Save();
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        App.LanguageChanged += LanguageChanged;
        SetLanguageMenu();
    }

    private void SetLanguageMenu()
    {
        CultureInfo currLang = App.Language;
        LangMenu.Items.Clear();
        foreach (var lang in App.Languages)
        {
            MenuItem menuLang = new MenuItem();
            Debug.WriteLine("Here is a display name: " + lang.DisplayName);
            menuLang.Header = lang.DisplayName;
            menuLang.Tag = lang;
            menuLang.IsChecked = lang.Equals(currLang);
            menuLang.Click += ChangeLanguageClick;
            LangMenu.Items.Add(menuLang);
        }
    }
    private void LanguageChanged(Object sender, EventArgs e)
    {
        //I've tried resseting LanguageMenu from here - no effect
        CultureInfo currLang = App.Language;
        foreach (MenuItem i in LangMenu.Items)
        {
            CultureInfo ci = i.Tag as CultureInfo;
            i.IsChecked = ci != null && ci.Equals(currLang);
        }
    }
    private void ChangeLanguageClick(Object sender, EventArgs e)
    {
        MenuItem mi = sender as MenuItem;
        if (mi != null)
        {
            CultureInfo lang = mi.Tag as CultureInfo;
            if (lang != null)
            {
                App.Language = lang;
                SetLanguageMenu();
            }
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfTestProject.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:WpfTestProject"
    mc:Ignorable="d"
    Title="{DynamicResource MainTitle}" Height="600" Width="800">
<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.Open" Executed="OpenCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.Save" Executed="SaveCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.SaveAs" Executed="SaveAsCommand_Executed"/>
</Window.CommandBindings>
<Window.InputBindings>
    <KeyBinding Key="N" Modifiers="Ctrl" Command="{Binding ApplicationCommands.New}"/>
    <KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding ApplicationCommands.Open}"/>
    <KeyBinding Key="S" Modifiers="Ctrl" Command="{Binding ApplicationCommands.Save}"/>
    <KeyBinding Key="S" Modifiers="Ctrl+Shift" Command="{Binding ApplicationCommands.SaveAs}"/>
</Window.InputBindings>
    <DockPanel Name="DockPanel" HorizontalAlignment="Stretch" LastChildFill="False" VerticalAlignment="Stretch">
        <MenuItem Command="ApplicationCommands.Open" Header="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Command.Text}"/>
        <MenuItem Name="LangMenu" Header="Languages" HorizontalAlignment="Right"/>
    </DockPanel>
</Window>

UPDATE

ResourceDictionary for English

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfTestProject.Properties"
                xmlns:v="clr-namespace:System;assembly=mscorlib">
<v:String x:Key="MainTitle">Title</v:String>

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
    <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="WpfTestProject.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
    </sectionGroup>
</configSections>
<startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<userSettings>
    <WpfTestProject.Properties.Settings>
        <setting name="DefaultLanguage" serializeAs="String">
            <value>en</value>
        </setting>
    </WpfTestProject.Properties.Settings>
</userSettings>

Any thoughts about what am I doing wrong?

The thing is that my MenuItem, which has it's Header set to the Text of Command bound to it, doesn't change Header according to CurrentUICulture.

Of course not, why would it?

You should set the Header of the MenuItem the same way as you set the localized text for the other elements:

<MenuItem Command="ApplicationCommands.Open" Header="{DynamicResource OpenText}"/>

Obviously you will have to do this for your localization to work across MenuItem elements as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM