• 使用.Net Core开发WPF App系列教程( 其他、实现多语言切换的几种方式)


    使用.Net Core开发WPF App系列教程

    一、.Net Core和WPF介绍

    二、在Visual Studio 2019中创建.Net Core WPF工程

    三、与.Net Framework的区别

    四、WPF中的XAML

    五、WPF中的布局

    六、WPF中的常用控件(上)

    其它、实现多语言切换的几种方式


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

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

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

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

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

    debugen-USStrResource.xml

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <Language>
    3     <Main_Title>Login Form</Main_Title>
    4     <Main_UserName>UserName</Main_UserName>
    5     <Main_Password>Password</Main_Password>
    6     <Main_Button>Login</Main_Button>
    7     <Window1_Title>Main Form</Window1_Title>
    8     <Window1_Label>Welcome</Window1_Label>
    9 </Language>

    debugzh-CNStrResource.xml

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <Language>
    3     <Main_Title>登陆窗体</Main_Title>
    4     <Main_UserName>用户名</Main_UserName>
    5     <Main_Password>密码</Main_Password>
    6     <Main_Button>登陆</Main_Button>
    7     <Window1_Title>主界面</Window1_Title>
    8     <Window1_Label>欢迎</Window1_Label>
    9 </Language>

    主窗体XAML

     1  <StackPanel>
     2         <Label Content="{Binding XPath=Main_UserName}"></Label>
     3         <TextBox></TextBox>
     4         <Label Name="Password" Content="{Binding XPath=Main_Password}"></Label>
     5         <TextBox></TextBox>
     6         <Button Height="20" Margin="10,5" Background="LightSkyBlue" Name="Login" Content="{Binding XPath=Main_Button}" Click="Login_Click"></Button>
     7         <ComboBox Name="combox" SelectedIndex="0" SelectionChanged="combox_SelectionChanged">
     8             <ComboBoxItem>中文</ComboBoxItem>
     9             <ComboBoxItem>English</ComboBoxItem>
    10         </ComboBox>
    11     </StackPanel>

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

    1 XmlDocument doc = new XmlDocument();
    2 XmlDataProvider xdp = new XmlDataProvider();
    3 doc.Load("./zh-CN/language.xml");  //在切换语言时,重新加载xml文档,并重新绑定到界面即可
    4 xdp.Document = doc;
    5 xdp.XPath = @"/Language";
    6 this.DataContext = xdp;

    运行效果如下:

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

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

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

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

    languageen-US.xaml

     1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     3                     xmlns:s="clr-namespace:System;assembly=mscorlib">
     4     <s:String x:Key="Main.Title">Main Form</s:String>
     5     <s:String x:Key="Main.RibbonTab.Setting">Setting</s:String>
     6     <s:String x:Key="Main.RibbonGroup.Setting">All Setting</s:String>
     7     <s:String x:Key="Main.RibbonButton.Setting">Setting</s:String>
     8     <s:String x:Key="Main.RibbonButton.Setting.Title">Setting</s:String>
     9     <s:String x:Key="Main.RibbonButton.Setting.Description">All Setting Include Language</s:String>
    10     <s:String x:Key="Setting.Title">Setting</s:String>
    11     <s:String x:Key="Setting.Tab.Language">Language Setting</s:String>
    12     <s:String x:Key="Setting.Tab.Label.ChooseLanguage">Please choose a language</s:String>
    13 </ResourceDictionary>

    languagezh-CN.xaml

     1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     3                     xmlns:s="clr-namespace:System;assembly=mscorlib">
     4     <s:String x:Key="Main.Title">主界面</s:String>
     5     <s:String x:Key="Main.RibbonTab.Setting">设置</s:String>
     6     <s:String x:Key="Main.RibbonGroup.Setting">全部设置</s:String>
     7     <s:String x:Key="Main.RibbonButton.Setting">设置</s:String>
     8     <s:String x:Key="Main.RibbonButton.Setting.Title">设置</s:String>
     9     <s:String x:Key="Main.RibbonButton.Setting.Description">包括语言在内的全部设置</s:String>
    10     <s:String x:Key="Setting.Title">设置</s:String>
    11     <s:String x:Key="Setting.Tab.Language">语言设置</s:String>
    12     <s:String x:Key="Setting.Tab.Label.ChooseLanguage">请选择一种语言</s:String>
    13 </ResourceDictionary>

    主窗体XAML

     1 <TabControl>
     2         <TabItem Header="{DynamicResource Setting.Tab.Language}">
     3             <StackPanel>
     4                 <TextBlock VerticalAlignment="Top" Margin="5,5,5,0" HorizontalAlignment="Left" Text="{DynamicResource Setting.Tab.Label.ChooseLanguage}">
     5                 </TextBlock>
     6                 <ComboBox Height="20"  VerticalAlignment="Top" Margin="5,10" Width="200" HorizontalAlignment="Left" Name="combox_Language" SelectionChanged="combox_Language_SelectionChanged">
     7                     <ComboBoxItem>中文</ComboBoxItem>
     8                     <ComboBoxItem>English</ComboBoxItem>
     9                 </ComboBox>
    10             </StackPanel>
    11         </TabItem>
    12     </TabControl>

    后台代码

     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

     1  <Grid>
     2         <Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="{x:Static local:StrResources.ChangeLanguage}"></Label>
     3         <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,5,0,0" Width="200" Name="combox_Culture">
     4             <ComboBoxItem Content="{x:Static local:StrResources.zh_CN}"></ComboBoxItem>
     5             <ComboBoxItem Content="{x:Static local:StrResources.en_US}"></ComboBoxItem>
     6         </ComboBox>
     7 
     8         <Button Content="{x:Static local:StrResources.OK}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,120,0"/>
     9         <Button Content="{x:Static local:StrResources.Cancel}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0"/>
    10     </Grid>

    主界面后台逻辑

     1  public partial class MainWindow : Window
     2     {
     3         public MainWindow()
     4         {
     5             InitializeComponent();
     6 
     7             LoadCulture();
     8         }
     9 
    10         public void LoadCulture()
    11         {
    12             if(CultureInfo.CurrentCulture.Name== "zh-CN")
    13             {
    14                 combox_Culture.SelectedIndex = 0;
    15             }
    16             else
    17             {
    18                 combox_Culture.SelectedIndex = 1;
    19             }
    20         }   
    21     }

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

     1    public partial class App : Application
     2     {
     3         private void Application_Startup(object sender, StartupEventArgs e)
     4         {
     5             //在这里可以更改语言
     6             ChangeCulture(0);
     7         }
     8 
     9         public void ChangeCulture(int index)
    10         {
    11             string cultureName = "";
    12 
    13             switch (index)
    14             {
    15                 case 0:
    16                     cultureName = "zh-CN";
    17                     break;
    18                 case 1:
    19                     cultureName = "en-US";
    20                     break;
    21                 default:
    22                     cultureName = "en-US";
    23                     break;
    24             }
    25 
    26             Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
    27             Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
    28         }
    29     }

    运行效果:

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

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

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

    debug目录下创建

    zh-CN.json

    1 {
    2   "OK": "确定",
    3   "Cancel": "取消",
    4   "ChangeLanguage": "更改语言",
    5   "zh_CN": "中文",
    6   "en_US": "English"
    7 }

    en-US.json

    1 {
    2   "OK": "OK",
    3   "Cancel": "Cancel",
    4   "ChangeLanguage": "Change language",
    5   "zh_CN": "中文",
    6   "en_US": "English"
    7 }

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

     1 /// <summary>
     2     /// 绑定通知类
     3     /// </summary>
     4     public class NotifyPropertyChanged : INotifyPropertyChanged
     5     {
     6         public event PropertyChangedEventHandler PropertyChanged;
     7 
     8         protected void RaisePropertyChanged(string PropertyName)
     9         {
    10             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    11         }
    12 
    13         protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
    14         {
    15             RaisePropertyChanged(PropertyName);
    16         }
    17 
    18         protected void RaiseAllChanged()
    19         {
    20             RaisePropertyChanged("");
    21         }
    22     }

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

     1  /// <summary>
     2     /// 语言字段类
     3     /// </summary>
     4     public class LanguageFields : NotifyPropertyChanged
     5     {
     6         /// <summary>
     7         /// 需要被重写的方法 用于获取语言字段值
     8         /// </summary>
     9         /// <param name="key"></param>
    10         /// <returns></returns>
    11         protected virtual string GetValue(string key) => "";
    12 
    13         protected virtual void SetValue(string Key, string value) { }
    14 
    15         /// <summary>
    16         /// 使用CallerMemberName特性传递当前属性名
    17         /// </summary>
    18         /// <param name="propertyName"></param>
    19         /// <returns></returns>
    20         string Get([CallerMemberName] string propertyName = null)
    21         {
    22             return GetValue(propertyName);
    23         }
    24 
    25         void Set(string value, [CallerMemberName] string propertyName = null)
    26         {
    27             SetValue(propertyName, value);
    28         }
    29 
    30         public string OK { get => Get(); set => Set(value); }
    31         public string Cancel { get => Get(); set => Set(value); }
    32         public string ChangeLanguage { get => Get(); set => Set(value); }
    33         public string zh_CN { get => Get(); set => Set(value); }
    34         public string en_US { get => Get(); set => Set(value); }
    35     }

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

     1  public class LanguageHelper : LanguageFields
     2     {   
     3         private JObject currentLanguage;           //当前语言的JObject对象 
     4         private static readonly string dir = Environment.CurrentDirectory;  //语言文件夹
     5         private CultureInfo currentCulture;   //当前语言
     6 
     7         public static LanguageHelper Instance { get; } = new LanguageHelper();
     8 
     9         LanguageHelper()
    10         {
    11             CurrentCulture = CultureInfo.CurrentCulture;
    12         }
    13 
    14         /// <summary>
    15         /// 当前语言属性 当值更新时,加载语言并更新绑定
    16         /// </summary>
    17         public CultureInfo CurrentCulture
    18         {
    19             get => currentCulture;
    20             set
    21             {
    22                 currentCulture = value;
    23                 CultureInfo.CurrentUICulture = value;
    24                 currentLanguage = LoadLang(value.Name); 
    25                 LanguageChanged?.Invoke(value);
    26                 RaiseAllChanged();
    27             }
    28         }
    29 
    30         /// <summary>
    31         /// 加载语言文件 
    32         /// </summary>
    33         /// <param name="LanguageId"></param>
    34         /// <returns></returns>
    35         JObject LoadLang(string LanguageId)
    36         {
    37             try
    38             {
    39                 var filePath = System.IO.Path.Combine(dir, $"{LanguageId}.json");
    40                 return JObject.Parse(File.ReadAllText(filePath));
    41             }
    42             catch
    43             {
    44                 return new JObject();
    45             }
    46         }
    47 
    48         /// <summary>
    49         /// 索引器方法 用于查找语言字段值
    50         /// </summary>
    51         /// <param name="Key"></param>
    52         /// <returns></returns>
    53         public string this[string Key]
    54         {
    55             get
    56             {
    57                 if (Key == null)
    58                     return "";
    59 
    60                 if (currentLanguage != null && currentLanguage.TryGetValue(Key, out var value) && value.ToString() is string s && !string.IsNullOrWhiteSpace(s))
    61                     return s;
    62 
    63                 return Key;
    64             }
    65         }
    66 
    67         /// <summary>
    68         /// 重写 GetValue方法,调用索引器方法 
    69         /// </summary>
    70         /// <param name="PropertyName"></param>
    71         /// <returns></returns>
    72         protected override string GetValue(string PropertyName) => this[PropertyName];
    73 
    74         /// <summary>
    75         /// 语言更改事件
    76         /// </summary>
    77         public event Action<CultureInfo> LanguageChanged;
    78     }

    主窗体XAML

     1  <Grid>
     2         <Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="{Binding ChangeLanguage, Source={StaticResource LangManger}, Mode=OneWay}"></Label>
     3         <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,5,0,0" Width="200" Name="combox_Culture" SelectionChanged="combox_Culture_SelectionChanged">
     4             <ComboBoxItem Content="{Binding zh_CN, Source={StaticResource LangManger}, Mode=OneWay}"></ComboBoxItem>
     5             <ComboBoxItem Content="{Binding en_US, Source={StaticResource LangManger}, Mode=OneWay}"></ComboBoxItem>
     6         </ComboBox>
     7 
     8         <Button Content="{Binding OK, Source={StaticResource LangManger}, Mode=OneWay}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,120,0"/>
     9         <Button Content="{Binding Cancel, Source={StaticResource LangManger}, Mode=OneWay}" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0"/>
    10     </Grid>

    主窗体后台逻辑

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

     1 public partial class MainWindow : Window
     2     {
     3         public MainWindow()
     4         {
     5             InitializeComponent();
     6 
     7             LanguageHelper.Instance.LanguageChanged += Instance_LanguageChanged;
     8             LoadCulture(LanguageHelper.Instance.CurrentCulture);
     9         }
    10 
    11         private void Instance_LanguageChanged(System.Globalization.CultureInfo obj)
    12         {
    13             //这里可以对语言更改进行处理
    14             switch(obj.Name)
    15             {
    16                 case "zh-CN":
    17                     break;
    18                 case "en-US":
    19                     break;
    20             }
    21         }
    22 
    23         private void LoadCulture(System.Globalization.CultureInfo culture)
    24         {
    25             switch(culture.Name)
    26             {
    27                 case "zh-CN":
    28                     combox_Culture.SelectedIndex = 0;
    29                     break;
    30                 case "en-US":
    31                     combox_Culture.SelectedIndex = 1;
    32                     break;
    33             }
    34         }
    35 
    36         private void combox_Culture_SelectionChanged(object sender, SelectionChangedEventArgs e)
    37         {
    38             var culture = "zh-CN";
    39 
    40             switch(combox_Culture.SelectedIndex)
    41             {
    42                 case 0:
    43                     culture = "zh-CN";
    44                     break;
    45                 case 1:
    46                     culture = "en-US";
    47                     break;
    48             }
    49 
    50             if (culture == null)
    51                 return;
    52 
    53             LanguageHelper.Instance.CurrentCulture = new System.Globalization.CultureInfo(culture.ToString().Replace("_", "-"));   //变量命名不支持 '-' ,所以这里需要替换一下
    54         }
    55     }

    示例代码

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

  • 相关阅读:
    jvm基本结构和解析
    多态的意思
    java中对象的简单解读
    double类型和int类型的区别
    python 解析xml文件
    win10不能映射Ubuntu共享文件
    Qt程序打包
    Ubuntu boot分区文件误删,系统无法启动,怎么解
    ubuntu Boot空间不够问题“The volume boot has only 5.1MB disk space remaining”
    Ubuntu 分辨率更改 xrandr Failed to get size of gamma for output default
  • 原文地址:https://www.cnblogs.com/zhaotianff/p/14042803.html
Copyright © 2020-2023  润新知