DotNetCore 3.0 助力 WPF本地化

概览

随着我们的应用程序越来越受欢迎,我们的下一步将要开发多语言功能。方便越来越多的国家使用我们中国的应用程序,基于 WPF 本地化,我们很多时候使用的是系统资源文件,可是动态切换本地化,就比较麻烦了。

实现思路

现在我们将要实现的是基于 DotNetCore 3.0 以上版本 and WPF 桌面应用程序模块化的多语言功能。动态切换多语言思路:

  • 把所有模块的资源文件添加到字典集合。

  • 将资源文件里的key,绑定到前台。

  • 通过通知更改 CurrentCulture 多语言来使用改变的语言文件里的key。

  • 通过绑定 Binding 拼接Path 在输出。

动态切换

我们先来看实现结果640?wx_fmt=gif

  • 第一行是我们的主程序的数据展示,用于业务中的本地化

  • 第二行是我们业务模块A的数据展示

  • 第三行是我们业务模块B的数据展示

来看一下xaml展示640?wx_fmt=png

通过ComboBox选择来切换语言640?wx_fmt=png

搭建模拟业务项目

创建一个WPF App(.NET Core)应用程序640?wx_fmt=png

创建完成后,我们需要引入业务A模块及业务B模块和业务帮助模块640?wx_fmt=png

使用ResX资源文件

在各个模块里添加Strings 文件夹用来包含 各个国家和地区的语言文件。

640?wx_fmt=png

多语言可以参考:https://github.com/UnRunDeaD/WPF---Localization/blob/master/ComboListLanguages.txt

资源文件可以放在任意模块内,比如业务模块A ,主程序,底层业务,控件工具集等

创建各个业务模块资源文件

Strings文件夹可以任意命名640?wx_fmt=png

帮助类

封装到底层供各个模块调用

    public class TranslationSource : INotifyPropertyChanged{public static TranslationSource Instance { get; } = new TranslationSource();private readonly Dictionary<string, ResourceManager> resourceManagerDictionary = new Dictionary<string, ResourceManager>();public string this[string key]{get{Tuple<string, string> tuple = SplitName(key);string translation = null;if (resourceManagerDictionary.ContainsKey(tuple.Item1))translation = resourceManagerDictionary[tuple.Item1].GetString(tuple.Item2, currentCulture);return translation ?? key;}}private CultureInfo currentCulture = CultureInfo.InstalledUICulture;public CultureInfo CurrentCulture{get { return currentCulture; }set{if (currentCulture != value){currentCulture = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));}}}public event PropertyChangedEventHandler PropertyChanged;public void AddResourceManager(ResourceManager resourceManager){if (!resourceManagerDictionary.ContainsKey(resourceManager.BaseName)){resourceManagerDictionary.Add(resourceManager.BaseName, resourceManager);}}public static Tuple<string, string> SplitName(string local){int idx = local.ToString().LastIndexOf(".");var tuple = new Tuple<string, string>(local.Substring(0, idx), local.Substring(idx + 1));return tuple;}}public class Translation : DependencyObject{public static readonly DependencyProperty ResourceManagerProperty =DependencyProperty.RegisterAttached("ResourceManager", typeof(ResourceManager), typeof(Translation));public static ResourceManager GetResourceManager(DependencyObject dependencyObject){return (ResourceManager)dependencyObject.GetValue(ResourceManagerProperty);}public static void SetResourceManager(DependencyObject dependencyObject, ResourceManager value){dependencyObject.SetValue(ResourceManagerProperty, value);}}public class LocExtension : MarkupExtension{public string StringName { get; }public LocExtension(string stringName){StringName = stringName;}private ResourceManager GetResourceManager(object control){if (control is DependencyObject dependencyObject){object localValue = dependencyObject.ReadLocalValue(Translation.ResourceManagerProperty);if (localValue != DependencyProperty.UnsetValue){if (localValue is ResourceManager resourceManager){TranslationSource.Instance.AddResourceManager(resourceManager);return resourceManager;}}}return null;}public override object ProvideValue(IServiceProvider serviceProvider){object targetObject = (serviceProvider as IProvideValueTarget)?.TargetObject;if (targetObject?.GetType().Name == "SharedDp")return targetObject;string baseName = GetResourceManager(targetObject)?.BaseName ?? string.Empty;if (string.IsNullOrEmpty(baseName)){object rootObject = (serviceProvider as IRootObjectProvider)?.RootObject;baseName = GetResourceManager(rootObject)?.BaseName ?? string.Empty;}if (string.IsNullOrEmpty(baseName)){if (targetObject is FrameworkElement frameworkElement){baseName = GetResourceManager(frameworkElement.TemplatedParent)?.BaseName ?? string.Empty;}}Binding binding = new Binding{Mode = BindingMode.OneWay,Path = new PropertyPath($"[{baseName}.{StringName}]"),Source = TranslationSource.Instance,FallbackValue = StringName};return binding.ProvideValue(serviceProvider);}}

前台绑定

640?wx_fmt=png


xmlns:ext="clr-namespace:WpfUtil.Extension;assembly=WpfUtil"xmlns:resx="clr-namespace:ModuleA.Strings"ext:Translation.ResourceManager="{x:Static resx:SR.ResourceManager}"

显示文字

<Label Content="{ext:Loc Test}" FontSize="21" />

后台实现

根据业务的需要,我们在界面上无法适用静态文字显示的,一般通过后台代码来完成,对于 code-behind 的变量使用,同样可以应用于资源字典。

PS: 欢迎各位大佬慷慨指点,有不足之处,请指出!有疑问,请指出,喜欢它,请支持!

下载地址

https://github.com/androllen/WpfNetCoreLocalization

相关链接

https://github.com/Jinjinov/wpf-localization-multiple-resource-resx-one-language/blob/master/README.md

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

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

相关文章

开源题材征集 + MVCEF Core 完整教程小结

到目前为止,我们的MVCEF Core 完整教程的理论部分就全部结束了,共20篇,覆盖了核心的主要知识点。下一阶段是实战部分,我们将会把这些知识点串联起来,用10篇(天)来完成一个开源项目。现向园友征集题材,你提需…

对微软的敌视何时休? 从一篇语言评论文章对C#的评价说起

看到一篇公众号文章《2020年什么编程语言最受欢迎,待遇最高?》,其中对C#的描述如下:点击阅读原文,看到这是一篇翻译文章:https://codinginfinite.com/top-programming-languages-2020-stats-surveys/这篇文…

ASP.NET Core on K8S深入学习(6)Health Check

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。预计阅读时间为10分钟。01—关于K8S中的健康监测所谓Health Check,就是健康检查,即防微杜渐。K8S是一个编排引擎可以帮助我们快捷地部署容器集…

关于 .Net Core runtimeconfig 文件说明

项目的bin\debug\netcoreapp${Version}下面能够找到这个${AppName}.runtimeconfig.json文件,简单来说,它就是用来定义应用程序所用的共享框架(.Net Core App)以及运行时选项 的一个文件。一个简单的例子{ "runtimeOptions&q…

net core 3.0 之Grpc新特性小试牛刀

作者: 相信微服务大家伙都有听说和知道,好处弊端咱也不多说了,Grpc算是一个比较全面的微服务框架,也得到微软的支持总结下来就是,跨平台,可靠,通信快,扩展性强,网络消耗小…

CF1168D Anagram Paths(由必要到充分/虚树)

CF1168D Anagram Paths 对于这道题首先有一个关键的性质,那就是对于一个树,它是可重排的,当且仅当在树上任意一个节点,所有字母在相关联的字符串中出现次数最大值之和小于当前点到叶子的距离。这个性质可以通过归纳证明&#xff0…

基于Coravel定时任务之计算总页数

在物联网系统中,需要计算底端所有设备的总数,除以分页每页显示数量,进行一个总页数的显示。包括状态,告警,日志等等数据都需要对应的总页数的显示。2.1 TaskSchedulerTaskScheduler库只支持.net,且需要结合…

Docker系列之AspNetCore Runtime VS .NetCore Runtime VS SDK(四)

接下来我们就要慢慢步入在.NET Core中使用Docker的殿堂了,如题在开始之前,我们需要搞清楚一些概念,要不然看到官方提供如下一系列镜像,我们会一脸懵逼,不知道到底要使用哪一个。AspNetCore Runtime VS .NetCore Runti…

.NET Core跨平台部署于Docker(Centos)- 视频教程

.NET Core跨平台部署于Docker,Docker部署于Centos中,演示跨平台特性!以下视频教程,请带上耳机开始聆听往期教程:.NET开发框架(一)-框架介绍与视频演示.NET开发框架(二)-框架功能简述.NET开发框架(三)-高可用服务器端设计.NET开发框…

【清华集训2014】Sum)(类欧几里得算法)

【清华集训2014】Sum 然后本质上我们需要求解的就是那个带根号式子的奇偶性,然后我们发现这个式子很像是类欧几里得算法,求解一个斜率为无理数直线下的整点个数,然后我们直接对于一般形式求解,那么就是每次利用整数部分将斜率减小…

一本让我多花2倍时间读的书

这里是Z哥的个人公众号每周五11:45 按时送达当然了,也会时不时加个餐~我的第「87」篇原创敬上Hi,大家好,我是Z哥。熟悉我的小伙伴应该知道,我平时看书大多都很快,之前还把自己的速读技巧分享给了…

[NOI2005]月下柠檬树 (自适应辛普森)

P4207 [NOI2005]月下柠檬树 如图,我们要求的面积就是这些圆形跟梯形的组合,由于投射到地面上,显然有h′htanθh \frac{h}{tan \theta}h′tanθh​,由此我们就可以开始推导这个f(x)f(x)f(x)函数了。 所以转换为我们要推导出直线a…

Kong 1.3发布,原生gRPC代理、上游TLS交叉认证

Kong 1.3 发布了,此版本亮点包括支持原生 gRPC 代理、上游 TLS 交叉认证,以及一系列新功能和性能改进。原生 gRPC 代理越来越多的用户转向微服务架构,并且希望有对原生 gRPC 代理的支持,Kong 1.3 解决了这个问题,为支持…

对Windows桌面应用程序进行UI自动化测试

所谓UI自动化测试,就是模拟一个用户,对应用程序的UI进行操作,以完成特定场景的功能性集成测试。要对Windows桌面应用程序进行UI自动化测试,目前可选的技术主要是两种:VS自带的CodedUI Test和AppiumWinAppDriver。但是&…

项目实战中如何使用抽象类和接口

引子:时常会有这么一个疑惑,抽象类和接口功能好像,真正用起来该如何抉择呢??好问题。。来看看书上怎么说的(C#7.0本质论)虽然方法可在基类中声明为抽象成员,但是!&#x…

番茄日志发布1.0.3版本-增加Kafka支持

番茄日志(TomatoLog)能做什么可能你是第一次听说TomatoLog,没关系,我可以从头告诉你,通过了解番茄日志,希望能帮助有需要的朋友,番茄日志处理将大大降低你采集、分析、处理日志的过程。介绍Toma…

ArangoDB 3.5发布:流事务API、蒙面数据、搜索性能大幅提升、最短路径功能

ArangoDB 3.5 发布了。ArangoDB 是一个分布式原生的多模型数据库,具有灵活的文档、图形和键值数据模型。使用方便的 SQL 查询语言或 JavaScript 扩展构建高性能应用程序。此版本亮点包括:期待已久的 Streaming Transactions API,可以直接使用…

ASP.NET Core on K8S深入学习(7)Dashboard知多少

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。在第二篇《部署过程解析与Dashboard》中介绍了如何部署Dashboard,但是没有更多地介绍如何使用Dashboard,本文就来对Dashboard的使用进行补充。…

【学习笔记】Docker - 02. 在容器中运行软件(上)

2.1 控制容器: 构建一个网站监视器 需求: 客户想让你做一个网站, 这个网站需要被紧密的监视, 如果服务器宕机了, 那么它们的团队会收到相关的邮件. 这里用到了3个容器. 第一个运行NGINX; 第二个运行一个叫做mailer的程序. 这两个容器都是detached的. Detached 表示容器将在后台…

lintcode 有效的括号序列

心血来潮,半夜做了一道Lintcode的题目,调试完睡觉,欢迎大家批评指正。 public boolean isValidParentheses(String s) {// Write your code hereStack stacknew Stack();if(s.length()0){return true;}else if(s.length()1){return false;}fo…