首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >深度盘点:WPF 多语言切换的 4 种方案

深度盘点:WPF 多语言切换的 4 种方案

作者头像
独立观察员
发布2025-11-13 18:55:50
发布2025-11-13 18:55:50
270
举报

在WPF中有多种方式可以实现多语言,这里提供几种常用的方式。

一、使用XML实现多语言切换

使用XML实现多语言的思路就是使用XML作为绑定的数据源。主要用到XmlDataProvider类.

使用XmlDataProvider.Source属性指定XML文件的路径或通过XmlDataProvider.Document指定XML文档对象,XmlDataProvider.XPath属性指定绑定的路径。

新建一个WPF工程,在debug目录下创建两个StrResource.xml文件,分别置于en-US和zh-CN文件夹

debug\en-US\StrResource.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<Language>
    <Main_Title>Login Form</Main_Title>
    <Main_UserName>UserName</Main_UserName>
    <Main_Password>Password</Main_Password>
    <Main_Button>Login</Main_Button>
    <Window1_Title>Main Form</Window1_Title>
    <Window1_Label>Welcome</Window1_Label>
</Language>

debug\zh-CN\StrResource.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<Language>
    <Main_Title>登陆窗体</Main_Title>
    <Main_UserName>用户名</Main_UserName>
    <Main_Password>密码</Main_Password>
    <Main_Button>登陆</Main_Button>
    <Window1_Title>主界面</Window1_Title>
    <Window1_Label>欢迎</Window1_Label>
</Language>

主窗体XAML

代码语言:javascript
复制
<StackPanel>
        <Label Content="{Binding XPath=Main_UserName}"></Label>
        <TextBox></TextBox>
        <Label Name="Password" Content="{Binding XPath=Main_Password}"></Label>
        <TextBox></TextBox>
        <Button Height="20" Margin="10,5" Background="LightSkyBlue" Name="Login" Content="{Binding XPath=Main_Button}" Click="Login_Click"></Button>
        <ComboBox Name="combox" SelectedIndex="0" SelectionChanged="combox_SelectionChanged">
            <ComboBoxItem>中文</ComboBoxItem>
            <ComboBoxItem>English</ComboBoxItem>
        </ComboBox>
</StackPanel>

后台代码中,将XmlDataProvider对象绑定到界面即可

代码语言:javascript
复制
XmlDocument doc = new XmlDocument();
XmlDataProvider xdp = new XmlDataProvider();
doc.Load("./zh-CN/language.xml");  //在切换语言时,重新加载xml文档,并重新绑定到界面即可
xdp.Document = doc;
xdp.XPath = @"/Language";
this.DataContext = xdp;

运行效果如下:

二、使用资源字典实现多语言切换

资源字典的实现方式也比较简单,这是最常用的一种方式。

主要实现步骤是:将要显示的字符绑定到资源文件,然后在切换语言时用代码更改当前使用的资源文件即可。

创建一个WPF工程,添加一个language目录,再添加en-US和zh-CN目录。再分别在目录下创建资源字典文件,内容如下:

language\en-US.xaml

代码语言:javascript
复制
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="clr-namespace:System;assembly=mscorlib">
    <s:String x:Key="Main.Title">Main Form</s:String>
    <s:String x:Key="Main.RibbonTab.Setting">Setting</s:String>
    <s:String x:Key="Main.RibbonGroup.Setting">All Setting</s:String>
    <s:String x:Key="Main.RibbonButton.Setting">Setting</s:String>
    <s:String x:Key="Main.RibbonButton.Setting.Title">Setting</s:String>
    <s:String x:Key="Main.RibbonButton.Setting.Description">All Setting Include Language</s:String>
    <s:String x:Key="Setting.Title">Setting</s:String>
    <s:String x:Key="Setting.Tab.Language">Language Setting</s:String>
    <s:String x:Key="Setting.Tab.Label.ChooseLanguage">Please choose a language</s:String>
</ResourceDictionary>

language\zh-CN.xaml

代码语言:javascript
复制
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="clr-namespace:System;assembly=mscorlib">
    <s:String x:Key="Main.Title">主界面</s:String>
    <s:String x:Key="Main.RibbonTab.Setting">设置</s:String>
    <s:String x:Key="Main.RibbonGroup.Setting">全部设置</s:String>
    <s:String x:Key="Main.RibbonButton.Setting">设置</s:String>
    <s:String x:Key="Main.RibbonButton.Setting.Title">设置</s:String>
    <s:String x:Key="Main.RibbonButton.Setting.Description">包括语言在内的全部设置</s:String>
    <s:String x:Key="Setting.Title">设置</s:String>
    <s:String x:Key="Setting.Tab.Language">语言设置</s:String>
    <s:String x:Key="Setting.Tab.Label.ChooseLanguage">请选择一种语言</s:String>
</ResourceDictionary>

主窗体XAML

代码语言:javascript
复制
<TabControl>
   <TabItem Header="{DynamicResource Setting.Tab.Language}">
       <StackPanel>
          <TextBlock VerticalAlignment="Top" Margin="5,5,5,0" HorizontalAlignment="Left" Text="{DynamicResource Setting.Tab.Label.ChooseLanguage}">
          </TextBlock>
          <ComboBox Height="20"  VerticalAlignment="Top" Margin="5,10" Width="200" HorizontalAlignment="Left" Name="combox_Language" SelectionChanged="combox_Language_SelectionChanged">
             <ComboBoxItem>中文</ComboBoxItem>
             <ComboBoxItem>English</ComboBoxItem>
           </ComboBox>
       </StackPanel>
   </TabItem>
</TabControl>

后台代码

代码语言:javascript
复制
private void combox_Language_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
      ChangeLanguage(this.combox_Language.SelectedIndex);
}


/// <summary>
/// 切换 语言
/// </summary>
/// <param name="index"></param>
public void ChangeLanguage(int index)
{
    ResourceDictionary rd = new ResourceDictionary();
    switch(index)
    {
        case 0:
           rd.Source = new Uri("Language/zh-CN.xaml", UriKind.Relative);
           break;
        case 1:
            rd.Source = new Uri("Language/en-US.xaml", UriKind.Relative);
            break;
        default:
            break;
    }            
    Application.Current.Resources.MergedDictionaries[0] = rd;
}

运行效果如下:

三、使用资源文件实现多语言切换

这种方式的实现也比较简单,也是将字符绑定到资源文件(.resx)

但需要注意的是,这种方式是静态的,不能实现动态切换。只能在启动时更改。

创建一个WPF工程,添加一个字符资源文件StrResources.resx作为默认的字符资源文件,再添加一个StrResources.zh-CN.resx做为中文字符资源(因为我用于演示的这台电脑系统是英文的)

注意:需要将访问修饰符改为public,否则运行会报错

主界面XAML

代码语言:javascript
复制
<Grid>
        <Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="{x:Static local:StrResources.ChangeLanguage}"></Label>
        <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,5,0,0" Width="200" Name="combox_Culture">
            <ComboBoxItem Content="{x:Static local:StrResources.zh_CN}"></ComboBoxItem>
            <ComboBoxItem Content="{x:Static local:StrResources.en_US}"></ComboBoxItem>
        </ComboBox>

        <Button Content="{x:Static local:StrResources.OK}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,120,0"/>
        <Button Content="{x:Static local:StrResources.Cancel}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0"/>
    </Grid>

主界面后台逻辑

代码语言:javascript
复制
public partial class MainWindow : Window
{
        public MainWindow()
        {
            InitializeComponent();

            LoadCulture();
        }

        public void LoadCulture()
        {
            if(CultureInfo.CurrentCulture.Name== "zh-CN")
            {
                combox_Culture.SelectedIndex = 0;
            }
            else
            {
                combox_Culture.SelectedIndex = 1;
            }
        }
}

在Application类的Startup事件中可以切换语言,但在程序运行后无法再切换

代码语言:javascript
复制
public partial class App : Application
{
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            //在这里可以更改语言
            ChangeCulture(0);
        }

        public void ChangeCulture(int index)
        {
            string cultureName = "";

            switch (index)
            {
                case 0:
                    cultureName = "zh-CN";
                    break;
                case 1:
                    cultureName = "en-US";
                    break;
                default:
                    cultureName = "en-US";
                    break;
            }

            Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
        }
}

运行效果:

四、使用json文件实现多语言切换

这种方式实现多语言切换有点麻烦,但可以使用json作为语言文件(其它格式文件其实也可以.txt .xml .csv)。

这种方式的实现原理是使用索引器方法查找每个字段值,然后绑定到界面上。支持动态切换

debug目录下创建

zh-CN.json

代码语言:javascript
复制
{
  "OK": "确定",
  "Cancel": "取消",
  "ChangeLanguage": "更改语言",
  "zh_CN": "中文",
  "en_US": "English"
}

en-US.json

代码语言:javascript
复制
{
  "OK": "OK",
  "Cancel": "Cancel",
  "ChangeLanguage": "Change language",
  "zh_CN": "中文",
  "en_US": "English"
}

封装一个绑定通知类,这个类用于切换语言时,绑定的通知更新。

代码语言:javascript
复制
/// <summary>
/// 绑定通知类
/// </summary>
public class NotifyPropertyChanged : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   protected void RaisePropertyChanged(string PropertyName)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
   }

   protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
   {
       RaisePropertyChanged(PropertyName);
   }

   protected void RaiseAllChanged()
   {
       RaisePropertyChanged("");
   }
}

创建一个语言字段类,这个类用于封装所有的语言字段。这一步确实就比较麻烦了,每个字段都得封装一个属性。

代码语言:javascript
复制
/// <summary>
/// 语言字段类
/// </summary>
public class LanguageFields : NotifyPropertyChanged
{
    /// <summary>
    /// 需要被重写的方法 用于获取语言字段值
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    protected virtual string GetValue(string key) => "";

    protected virtual void SetValue(string Key, string value) { }

    /// <summary>
    /// 使用CallerMemberName特性传递当前属性名
    /// </summary>
    /// <param name="propertyName"></param>
    /// <returns></returns>
    string Get([CallerMemberName] string propertyName = null)
    {
        return GetValue(propertyName);
    }

    void Set(string value, [CallerMemberName] string propertyName = null)
    {
        SetValue(propertyName, value);
    }

    public string OK { get => Get(); set => Set(value); }
    public string Cancel { get => Get(); set => Set(value); }
    public string ChangeLanguage { get => Get(); set => Set(value); }
    public string zh_CN { get => Get(); set => Set(value); }
    public string en_US { get => Get(); set => Set(value); }
}

创建一个语言切换帮助类,这个类可以对当前使用的语言以及字段值进行操作

代码语言:javascript
复制
public class LanguageHelper : LanguageFields
    {
        private JObject currentLanguage;           //当前语言的JObject对象
        private static readonly string dir = Environment.CurrentDirectory;  //语言文件夹
        private CultureInfo currentCulture;   //当前语言

        public static LanguageHelper Instance { get; } = new LanguageHelper();

        LanguageHelper()
        {
            CurrentCulture = CultureInfo.CurrentCulture;
        }

        /// <summary>
        /// 当前语言属性 当值更新时,加载语言并更新绑定
        /// </summary>
        public CultureInfo CurrentCulture
        {
            get => currentCulture;
            set
            {
                currentCulture = value;
                CultureInfo.CurrentUICulture = value;
                currentLanguage = LoadLang(value.Name);
                LanguageChanged?.Invoke(value);
                RaiseAllChanged();
            }
        }

        /// <summary>
        /// 加载语言文件
        /// </summary>
        /// <param name="LanguageId"></param>
        /// <returns></returns>
        JObject LoadLang(string LanguageId)
        {
            try
            {
                var filePath = System.IO.Path.Combine(dir, $"{LanguageId}.json");
                return JObject.Parse(File.ReadAllText(filePath));
            }
            catch
            {
                return new JObject();
            }
        }

        /// <summary>
        /// 索引器方法 用于查找语言字段值
        /// </summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        public string this[string Key]
        {
            get
            {
                if (Key == null)
                    return "";

                if (currentLanguage != null && currentLanguage.TryGetValue(Key, out var value) && value.ToString() is string s && !string.IsNullOrWhiteSpace(s))
                    return s;

                return Key;
            }
        }

        /// <summary>
        /// 重写 GetValue方法,调用索引器方法
        /// </summary>
        /// <param name="PropertyName"></param>
        /// <returns></returns>
        protected override string GetValue(string PropertyName) => this[PropertyName];

        /// <summary>
        /// 语言更改事件
        /// </summary>
        public event Action<CultureInfo> LanguageChanged;
    }

主窗体XAML

代码语言:javascript
复制
<Grid>
   <Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="{Binding ChangeLanguage, Source={StaticResource LangManger}, Mode=OneWay}"></Label>
   <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,5,0,0" Width="200" Name="combox_Culture" SelectionChanged="combox_Culture_SelectionChanged">
       <ComboBoxItem Content="{Binding zh_CN, Source={StaticResource LangManger}, Mode=OneWay}"></ComboBoxItem>
       <ComboBoxItem Content="{Binding en_US, Source={StaticResource LangManger}, Mode=OneWay}"></ComboBoxItem>
    </ComboBox>

    <Button Content="{Binding OK, Source={StaticResource LangManger}, Mode=OneWay}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,120,0"/>
    <Button Content="{Binding Cancel, Source={StaticResource LangManger}, Mode=OneWay}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0"/>
</Grid>

主窗体后台逻辑

软件启动时,加载当前语言。当下位框切换时,切换语言。

代码语言:javascript
复制
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        LanguageHelper.Instance.LanguageChanged += Instance_LanguageChanged;
        LoadCulture(LanguageHelper.Instance.CurrentCulture);
    }

    private void Instance_LanguageChanged(System.Globalization.CultureInfo obj)
    {
        //这里可以对语言更改进行处理
        switch(obj.Name)
        {
            case "zh-CN":
                break;
            case "en-US":
                break;
        }
    }

    private void LoadCulture(System.Globalization.CultureInfo culture)
    {
        switch(culture.Name)
        {
            case "zh-CN":
                combox_Culture.SelectedIndex = 0;
                break;
            case "en-US":
                combox_Culture.SelectedIndex = 1;
                break;
        }
    }

    private void combox_Culture_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var culture = "zh-CN";

        switch(combox_Culture.SelectedIndex)
        {
            case 0:
                culture = "zh-CN";
                break;
            case 1:
                culture = "en-US";
                break;
        }

        if (culture == null)
            return;

        LanguageHelper.Instance.CurrentCulture = new System.Globalization.CultureInfo(culture.ToString().Replace("_", "-"));   //变量命名不支持 '-' ,所以这里需要替换一下
    }
}

示例代码

https://github.com/zhaotianff/DotNetCoreWPF/tree/master/其它、实现多语言切换的几种方式/MultiLanguageDemo

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-09-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 独立观察员博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档