WPF本地化/国际化,多语言切换

news2024/10/6 10:33:54

之前写过winformwinform使用本地化,中英文切换_winform 中英文切换_故里2130的博客-CSDN博客

基本的技术差不多,但是后来又发现了一个ResXManager工具,可以更好方便快捷的使用。

首先下载,网络不好的话,去官网下载,然后安装,重启vs即可

wpf做多语言切换

有很多种,可以使用自带的资源去做,就是使用xaml写key值,这种做法是最简单方便的,也是wpf独特使用的,如果有大量的翻译,那么需要人工去翻译,需要转折一次,此种方法就不说了。下面说2种使用.resx资源和ResXManager工具来做。唯一的好处,就是自带翻译功能,方便快捷。

第一种

1.此处使用.net6创建wpf项目,与.net framework不一样,.net framework要简单一些

建立如图项目

2.打开ResXManager工具

3.点击新增语言,增加几个语种

增加后,双击增加的语种,就会自动生成对应的.resx文件,想要多少种语言,就可以增加多少种

最后要修改一下后缀名,否则报错。

4. 点击翻译

此处,可以导出Excel,让别人翻译,然后再导入,也可以使用在线翻译的功能,点击翻译。

  

5.效果

6. 创建LanguageManager.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Resources;
using System.Text;

namespace WpfApp1.Resources
{
    public class LanguageManager : INotifyPropertyChanged
    {
        /// <summary>
        /// 资源
        /// </summary>
        private readonly ResourceManager _resourceManager;

        /// <summary>
        /// 懒加载
        /// </summary>
        private static readonly Lazy<LanguageManager> _lazy = new Lazy<LanguageManager>(() => new LanguageManager());   
        public static LanguageManager Instance => _lazy.Value;
        public event PropertyChangedEventHandler PropertyChanged;

        public LanguageManager()
        {
            //获取此命名空间下Resources的Lang的资源,Lang可以修改
            _resourceManager = new ResourceManager("WpfApp1.Resources.Lang", typeof(LanguageManager).Assembly);
        }

        /// <summary>
        /// 索引器的写法,传入字符串的下标
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public string this[string name]
        {
            get
            {
                if (name == null)
                {
                    throw new ArgumentNullException(nameof(name));
                }
                return _resourceManager.GetString(name);
            }
        }

        public void ChangeLanguage(CultureInfo cultureInfo)
        {
            CultureInfo.CurrentCulture = cultureInfo;
            CultureInfo.CurrentUICulture = cultureInfo;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("item[]"));  //字符串集合,对应资源的值
        }
    }
}

7.xaml界面

<Window x:Class="WpfApp1.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:WpfApp1.Resources"
        mc:Ignorable="d"
        xmlns:res="clr-namespace:System.Windows.Resources;assembly=PresentationFramework"
       
        Title="MainWindow" Height="450" Width="800">
    <StackPanel HorizontalAlignment="Center">
        <ComboBox x:Name="LanguageList" SelectedIndex="0" Margin="10" SelectionChanged="LanguageList_SelectionChanged"/>
        <!--这里绑定字符串的值,Source来源于语言的集合,Mode是响应的方式,有些需要,有些不需要-->
        <TextBlock FontSize="20" Margin="10" Text="{Binding [String1], Source={x:Static local:LanguageManager.Instance}}"/>
        <TextBox FontSize="20" Margin="10"   Text="{Binding [String2], Source={x:Static local:LanguageManager.Instance}, Mode=OneWay}"/>
        <Button FontSize="20" Margin="10" Content="{Binding [String3], Source={x:Static local:LanguageManager.Instance}}"/>
    </StackPanel>
</Window>

8.后台

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfApp1.Resources;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LanguageList.ItemsSource = new List<string>
            {
                "en-Us",
                "zh-CN",
                "ar"
            };
  //this.DataContext = new Lazy<LanguageManager>(() => new LanguageManager()).Value;
        }

        /// <summary>
        /// 下拉框赋值语言的类型
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LanguageList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            LanguageManager.Instance.ChangeLanguage(new CultureInfo((sender as ComboBox).SelectedItem.ToString()));
        }
    }
}

此处使用mvvm的话,可以直接绑定,1对1绑定语言 

9.效果

第二种

1.首先创建一个程序

2.在Resources文件夹中,创建文件

3.GlobalClass.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp2.Resources
{
    /// <summary>
    /// 全局类
    /// </summary>
    public static class GlobalClass
    {
        static bool? inDesignMode = null;
        /// <summary>
        /// 判断是设计器还是程序运行
        /// </summary>
        public static bool InDesignMode
        {
            get
            {
                if (inDesignMode == null)
                {
#if SILVERLIGHT
                    inDesignMode = DesignerProperties.IsInDesignTool;
#else
                    var prop = DesignerProperties.IsInDesignModeProperty;
                    inDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;

                    if (!inDesignMode.GetValueOrDefault(false) && Process.GetCurrentProcess().ProcessName.StartsWith("devenv", StringComparison.Ordinal))
                        inDesignMode = true;
#endif
                }

                return inDesignMode.GetValueOrDefault(false);
            }
        }
        /// <summary>
        /// 语言改变通知事件
        /// </summary>
        public static EventHandler<EventArgs> LanguageChangeEvent;
        static Resource StringResource;
        static GlobalClass()
        {
            StringResource = new Resource();
        }
        /// <summary>
        /// 获取资源内容
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetString(string key)
        {
            return StringResource.GetString(key);
        }
        /// <summary>
        /// 改变语言
        /// </summary>
        /// <param name="language">CultureInfo列表(http://www.csharpwin.com/csharpspace/8948r7277.shtml)</param>
        public static void ChangeLanguage(string language)
        {
            CultureInfo culture = new CultureInfo(language);
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;

            StringResource.CurrentCulture = culture;

            if (LanguageChangeEvent != null)
            {
                LanguageChangeEvent(null, null);
            }
        }
    }
}

4.Resource.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Resources;

namespace WpfApp2.Resources
{
    public interface IResource
    {
        string GetString(string name);
        CultureInfo CurrentCulture { set; }
    }
    public class Resource : IResource
    {
        private ResourceManager stringResource;
        //我们这样设置的时候ResourceManager会去查找MultilanguageTest.StringResource.en-us.resx,如果没有会查找MultilanguageTest.StringResource.resx
        private CultureInfo culture = new CultureInfo("zh-cn");     //默认值
        public Resource()
        {
            //MultilanguageTest.StringResource是根名称,该实例使用指定的System.Reflection.Assmbly查找从指定的跟名称导出的文件中包含的资源
            //此处注意WpfApp2.Resources.Lang,Lang是资源文件的名字
            stringResource = new ResourceManager("WpfApp2.Resources.Lang", typeof(Resource).Assembly);
        }
        /// <summary>
        /// 通过资源名称获取资源内容
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetString(string name)
        {
            return stringResource.GetString(name, culture);
        }
        /// <summary>
        /// 改变当前的区域信息,ResourceManager可以通过当前区域信息去查找.resx文件
        /// </summary>
        public CultureInfo CurrentCulture
        {
            set
            {
                culture = value;
            }
        }
    }
}

5.StringResourceExtension.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace WpfApp2.Resources
{
    [MarkupExtensionReturnType(typeof(BindingExpression))]
    public class StringResourceExtension : MarkupExtension, INotifyPropertyChanged
    {
        /// <summary>
        /// 资源的名称,与资源文件StringResource.resx对应
        /// </summary>
        [ConstructorArgument("key")]
        public string Key
        {
            get;
            set;
        }
        string _DefaultValue;
        /// <summary>
        /// 默认值,为了使在设计器的情况时把默认值绑到设计器
        /// </summary>
        public string DefaultValue
        {
            get
            {
                return _DefaultValue;
            }
            set
            {
                _DefaultValue = value;
            }
        }
        string _Value;
        /// <summary>
        /// 资源的具体内容,通过资源名称也就是上面的Key找到对应内容
        /// </summary>
        public string Value
        {
            get
            {
                ///如果为设计器模式,本地的资源没有实例化,我们不能从资源文件得到内容,所以从KEY或默认值绑定到设计器去
                if (GlobalClass.InDesignMode)
                {
                    if (Key != null && DefaultValue != null)
                        return DefaultValue;
                    if (Key == null && DefaultValue != null)
                        return DefaultValue;
                    if (Key != null && DefaultValue == null)
                        return Key;
                    if (Key == null && DefaultValue == null)
                        return "NULL";
                }
                else
                {
                    if (Key != null)
                    {
                        string strResault = null;
                        try
                        {
                            strResault = GlobalClass.GetString(Key);
                        }
                        catch
                        {
                        }
                        if (strResault == null)
                        {
                            strResault = _DefaultValue;
                        }
                        return strResault;
                    }
                }
                return _Value;
            }
            set
            {
                _Value = value;
            }
        }
        public StringResourceExtension(string key)
            : this()
        {
            Key = key;
            GlobalClass.LanguageChangeEvent += new EventHandler<EventArgs>(Language_Event);
        }
        public StringResourceExtension(string key, string DefaultValue)
            : this()
        {
            Key = key;
            _DefaultValue = DefaultValue;
            GlobalClass.LanguageChangeEvent += new EventHandler<EventArgs>(Language_Event);

        }
        public StringResourceExtension()
        {
        }
        /// <summary>
        /// 每一标记扩展实现的 ProvideValue 方法能在可提供上下文的运行时使用 IServiceProvider。然后会查询此 IServiceProvider 以获取传递信息的特定服务
        ///当 XAML 处理器在处理一个类型节点和成员值,且该成员值是标记扩展时,它将调用该标记扩展的 ProvideValue 方法并将结果写入到对象关系图或序列化流,XAML 对象编写器将服务环境通过 serviceProvider 参数传递到每个此类实现。
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

            Setter setter = target.TargetObject as Setter;
            if (setter != null)
            {
                return new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
            }
            else
            {
                Binding binding = new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
                return binding.ProvideValue(serviceProvider);
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        static readonly System.ComponentModel.PropertyChangedEventArgs
            valueChangedEventArgs = new System.ComponentModel.PropertyChangedEventArgs("Value");

        protected void NotifyValueChanged()
        {
            if (PropertyChanged != null)
                PropertyChanged(this, valueChangedEventArgs);
        }
        /// <summary>
        /// 语言改变通知事件,当程序初始化的时候会绑定到全局的GlobalClass.LanguageChangeEvent事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Language_Event(object sender, EventArgs e)
        {
            //通知Value值已经改变,需重新获取
            NotifyValueChanged();
        }
    }
}

6.创建3个语言的文件

使用ResXManager工具进行翻译,参考上面的细节

7.效果

2种方式都可以,第一种要简单一点。 

源码:

https://download.csdn.net/download/u012563853/87944124

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

01背包简介

01背包问题&#xff08;0/1 Knapsack problem&#xff09;是一个经典的动态规划问题&#xff0c;它描述了在给定容量限制的情况下&#xff0c;如何选择一组物品放入背包&#xff0c;以使得物品的总价值最大化。 问题描述&#xff1a; 假设有一个背包&#xff0c;其容量为C。现…

VulnHub项目:Fawkes

1、靶机地址 HarryPotter: Fawkes ~ VulnHub 该篇为哈利波特死亡圣器系列最终部&#xff0c;也是最难的一个靶机&#xff0c;难度真的是逐步提升&#xff01;&#xff01;&#xff01; 2、渗透过程 确认靶机IP&#xff0c;kali IP&#xff0c;探测靶机开放端口 详细的扫描…

ICLR 23 | 工业视觉小样本异常检测最新网络:Graphcore

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://openreview.net/pdf?idxzmqxHdZAwO 论文代码&#xff1a;尚未开源 1.背景 随着人工智能中深度视觉检测技术的快速发展&#xff0c;检测工业产品表面的异常/缺陷受到了前所未有…

scratch lenet(11): C语言实现 squashing function

文章目录 1. 目的2. Sigmoidal Function2.1 S2 用到 Sigmoidal Function2.2 Sigmoidal Function 的定义 3. Squashing Function3.1 改用 Sigmoid Suahsing function 术语3.2 具体到 hyperlolic tangent 这一 squahsing function 4. Squahsing function 的实现References 1. 目的…

设计模式之观察者模式笔记

设计模式之观察者模式笔记 说明Observer(观察者)目录观察者模式示例类图抽象主题角色类抽象观察者类具体主题角色类具体的观察者角色类测试类 说明 记录下学习设计模式-观察者模式的写法。JDK使用版本为1.8版本。 Observer(观察者) 意图:定义对象间的一种一对多的依赖关系&a…

Gradle构建系统macOS安装与使用

1.打开gradle.org并点击安装 2.先决条件 ,确认安装JDK1.8或者更高版本已安装 在终端输入brew install gradle进行安装 安装成功如下: 查看安装版本号gradle -v 使用gradle 1.创建目录demo并进入该目录 mkdir demo cd demo 2.gradle init 使用Gradle开始构建 输入2开始构建应…

DevOps系列文章之 docker插件实现多实例部署(IDEA插件)

1. Docker的安装以及开启远程访问 1.1 安装 # 检查虚拟机内核版本&#xff0c;必须是3.10及以上 uname -r # 安装docker yum install docker # 输入y确认安装 # 启动docker systemctl start docker # 查看docker版本 docker -v # 开机启动docker systemctl enable docker # 停…

Golang学习日志 ━━ gin-vue-admin换机重新配置的记录,很愚蠢,很傻瓜,很机械...自己使用

最近一直在弄AI&#xff0c;没时间搞gva&#xff0c;所以有点忘记了&#xff0c;代码升级管它呢&#xff0c;全部重来一遍~ 一、备份保存 根据经验和个人喜好&#xff0c;我特别不喜欢在框架下把一个应用分散在module、api、service等等目录下&#xff0c;这种目录分配方案将把…

图上作业法

目录 交通示意图的表示方法 图上作业法 &#xff08;1&#xff09;对流 &#xff08;2&#xff09;迂回 物资调运问题的图上作业法 交通路线不成圈 交通路线成圈 交通示意图的表示方法 交通示意图是用来表明收发点的大致位置、收发量、交通路线长度的图形。 图形表示…

java mail发送、接收邮件

java mail接收邮件 1、引入java mail依赖 <dependency><groupId>org.eclipse.angus</groupId><artifactId>angus-mail</artifactId><version>2.0.2</version> </dependency>2、编写代码 注意&#xff1a;下述代码中的服务器…

从BNO055传感器获取IMU数据-2

在前面的文章 从BNO055传感器获取IMU数据-1 中介绍了BNO055传感器&#xff0c;今天继续讲解应用示例。 传感器与Arduino接口 我从某宝购买了固定在带有支持组件的开发板上的 BNO055 传感器。从 Digi-Key 或贸泽购买 BNO055 并将其焊接到 7.54.4mm 28 引脚 LGA 至 DIP 转换器上…

Groovy基础

Groovy基础 学Groovy有什么用&#xff1f;&#xff1f;&#xff1f;一、Groovy简介二、Mac安装Groovy1、使用homebrew安装或官网下载2、配置环境变量3、重新加载环境变量 二、Groov基本语法三、更多特性和扩展四、Groovy简单使用1、Groovy中的字符串及三大语句结构2、Groovy类与…

1带你入门MATLAB图像处理图像类型转换(附matlab程序)

1.简述 学习目标&#xff1a; 图像类型的转换 常用图像格式 图像格式&#xff1a;是存储图像采用的文件格式。不同的操作系统、不同的图像处理软件&#xff0c;所支持的图像格式都有可能不同。 在实际应用中经常会遇到的图像格式有&#xff1a;BMP、GIF、TIFF、PCX、JPEG、P…

FFmpeg5.0源码阅读——avformat_open_input

摘要&#xff1a;本文主要描述了FFmpeg中用于打开文件接口avformat_open_input的具体调用流程&#xff0c;详细描述了该接口被调用时所作的具体工作。   关键字&#xff1a;ffmpeg、avformat_open_input   注意&#xff1a;读者需要了解FFmpeg的基本使用流程&#xff0c;以…

力扣动态规划专题(五)子序列问题 不连续子序列与连续子序列 步骤及C++实现

文章目录 300.最长递增子序列674.最长连续递增子序列动态规划贪心算法 718. 最长重复子数组二维dp数组一维dp数组 1143.最长公共子序列1035.不相交的线53. 最大子序和动态规划贪心算法 300.最长递增子序列 步骤 确定dp数组以及下标的含义 dp[i]&#xff1a;i之前&#xff08;包…

【数据结构】单链表 创建 插入 删除 查找 完整代码

3.1 单链表 3.1.1 定义 注&#xff1a; 元素离散的分布在存储空间中&#xff0c;所以单链表是非随机存取的存储结构。 即不能直接找到表中某个特定的结点&#xff0c;需要从表头开始遍历&#xff0c;依次查找。 定义的代码 typedef struct LNode {ElemType data;//每个节点存放…

第三章 处理机调度与死锁

目录 一、调度的概念、层次 2.1 调度的基本概念 2.2 调度的三个层次 2.2.1 高级调度 2.2.2 低级调度 2.2.3 中级调度 2.2.3.1 进程的挂起态 2.2.4 三层调度的联系、对比 二、进程调度的时机、切换与过程、方式 2.1 进程调度的时机 2.2 进程调度的方式 2.2.1 非抢占…

计网复习题

一、单项选择题 OSI参考模型的物理层负责&#xff08;&#xff09;。 A&#xff0e;格式化报文 B&#xff0e;为数据选择通过网络的路由(网络层) C&#xff0e;定义连接到介质的特性 D&#xff0e;提供远程文件访问能力(应用层) 下列选项中&#xff0c;不属于网络体系结构中所…

常用git操作总结

文章目录 一、git 分支命名规范&#xff08;1&#xff09;master 主分支&#xff08;2&#xff09;develop 开发分支&#xff08;3&#xff09;feature 分支&#xff08;一般简写为feat&#xff09;&#xff08;4&#xff09;hotfix 分支&#xff08;一般简写为fix&#xff09;…