WPF:如何在运行时更改CurrentUICulture

16

我正在尝试在单击事件中更改我的 WPF 应用程序使用的语言,但它没有变化。

private void menuItemGerman_Click(object sender, RoutedEventArgs e)
{
   Settings.Default.Culture = "de-DE";

   Thread.CurrentThread.CurrentCulture = new CultureInfo(Settings.Default.Culture);
   Thread.CurrentThread.CurrentUICulture = new CultureInfo(Settings.Default.Culture);
}

我漏掉了什么?


4
更改文化并不能自动翻译您的用户界面文本。虽然会做一些其他事情,但并不包括这个。您是否提供了任何德语文本翻译? - Tim Lloyd
4个回答

11

我错过了什么?

你更改了线程所注册的文化,现在String.Format将使用这个新的文化,但是你需要重新加载WPF层次结构中的所有本地化项目。

WPF本地化 - 动态语言选择有更多信息。


7
你的链接损坏了 :( - conterio
1
链接已经失效了,我也很期待这个。 - Luishg
2
conterio: Luishg: https://web.archive.org/web/20130716022025/http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection.aspx康特里奥:Luishg:https://web.archive.org/web/20130716022025/http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection.aspx - riQQ

4
如果你有资源文件,例如:
  • Resources.resx
  • Resources.hu-hu.resx
并且想在运行时更改本地化设置, 而且不想搞混其他资源词典和重新编码所有的UI本地化, 那么可以使用
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);

但是它不会改变已显示窗口的语言。

为了实现这一点,需要进行更多编码-必须管理应用程序生命周期,而不是使用默认设置。

首先,请从App.xaml中删除StartupUri:

<Application
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         x:Class="ADUI.App"
         xmlns:System="clr-namespace:System;assembly=mscorlib" >
     <!--StartupUri="wndMain.xaml">-->
<Application.Resources>
</Application.Resources>

其次,实现一个类,该类现在负责应用程序的生命周期:
public class LocApp: Application
{
    [STAThread]
    public static void Main()
    {
        App app = new App();
        app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
        wndMain wnd = new wndMain();
        wnd.Closed += Wnd_Closed;
        app.Run(wnd);
    }

    private static void Wnd_Closed(object sender, EventArgs e)
    {
        wndMain wnd = sender as wndMain;
        if (!string.IsNullOrEmpty(wnd.LangSwitch))
        {
            string lang = wnd.LangSwitch;

            wnd.Closed -= Wnd_Closed;

            Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);

            wnd = new wndMain();
            wnd.Closed += Wnd_Closed;
            wnd.Show();
        }
        else
        {
            App.Current.Shutdown();
        }
    }
}

请不要忘记在项目属性/应用程序页面更改启动对象为LocApp!

最后,在主窗口的代码中实现一些可以切换语言的代码:

public partial class wndMain : Window
{
    public string LangSwitch { get; private set; } = null;

    // ... blah, blah, blah

    private void tbEn_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        LangSwitch = "en";
        Close();
    }

    private void tbHu_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        LangSwitch = "hu-hu";
        Close();
    }

    // ... blah, blah, blah

}

确保提供的本地化代码与resx文件语言代码之一匹配(例如,在此示例中为“hu-hu”)!

此解决方案将使用选择的语言关闭并重新打开主窗口,并在主窗口由其他方式关闭时退出。


这个解决方案非常有帮助,虽然并不总是需要创建一个新的 Application 类,我们可以将这个逻辑添加到现有的实现中。关键在于使用 ShutdownMode.OnExplicitShutdown 来使其正常工作。如果没有它,应用程序将在主窗体关闭时关闭。 - Chris Schaller

0

这可能对某些人有用。我已经使用George和Chris Schaller提供的建议,在我的项目中使其工作,而不需要创建新的Application类。

public string LangSwitch { get; private set; } = null;    
private void BtnLngPl_Click(object sender, RoutedEventArgs e)
        {
            CultureInfo current = CultureInfo.CurrentUICulture;
            CultureInfo newUiCulture;
            if (current.Name.Equals("en-US"))
            {
                newUiCulture = new CultureInfo("pl");
                Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
                if (System.Windows.Application.Current.MainWindow != null)
                    ((MainWindow)System.Windows.Application.Current.MainWindow).Closed += Wnd_Closed;
                Thread.CurrentThread.CurrentCulture = newUiCulture;
                Thread.CurrentThread.CurrentUICulture = newUiCulture;
                LangSwitch = "pl";
                Close();
            }
            else
                newUiCulture = new CultureInfo("en-US");

            CultureInfo.CurrentUICulture = newUiCulture;
            Console.WriteLine(@"The current UI culture is now {0}",
                CultureInfo.CurrentUICulture.Name);
        }

其它必要的代码可以从乔治的回答中获取。不确定这是否是一个好的解决方案,但对我来说起作用。


0

我也遇到过这个问题,我的解决方案是:

  • Resources.en-US
  • Resources.pt-PT
我创建了一个类,它将返回一个包含键和标签的字典:
public class Labels : ObservableObject
{
    public Dictionary<string, string> Items { get; set; }
    public string this[string name]
    {
        get
        {
            return Items.ContainsKey(name) ? Items[name] : "";
        }
    }

    public Labels()
    {
        Items = new Dictionary<string, string>();
    }
}

接下来,还需要一个类来获取资源:
public static class LanguageUtils
{
    public static Labels GetLangLables(string label)
    {
        var resources = Resources.ResourceManager.GetResourceSet(new CultureInfo(label), true, true);
        return new Labels
        {
            Items = resources.Cast<DictionaryEntry>().ToDictionary(r => r.Key.ToString(), r => r.Value.ToString())
        };
    }
}

当你需要某种语言时:

LanguageUtils.GetLangLables("pt-PT");

如果你无法提升(RaisePropertyChanged())静态属性,请使用以下方法:

public class LanguageContext
{
    private static LanguageContext _languageContext;
    public static LanguageContext Instance
    {
        get
        {
            if (_languageContext == null)
            {
                _languageContext = new LanguageContext();
            }

            return _languageContext;
        }
    }

    protected LanguageContext()
    {
        CurrentLangLabels = LanguageUtils.GetLangLables("en-US");
     }
     public Labels CurrentLangLabels { get; set; }
}

现在你可以更新语言:

LanguageContext.Instance.CurrentLangLabels = LanguageUtils.GetLangLables(SelectedLanguage.Resource);

像这样抛出异常:

public Labels CurrentLangLabels
{
   get { return LanguageContext.Instance.CurrentLangLabels; }
   set { RaisePropertyChanged(); }
}

并使用标签:

CurrentLangLabels.Items[LabelName]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接