概览

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

实现思路

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

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

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

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

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

动态切换

我们先来看实现结果

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

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

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

来看一下xaml展示

通过ComboBox选择来切换语言

搭建模拟业务项目

创建一个WPF App(.NET Core)应用程序

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

使用ResX资源文件

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

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

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

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

Strings文件夹可以任意命名

帮助类

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

    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);}}

前台绑定


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

DotNetCore 3.0 助力 WPF本地化相关推荐

  1. DotNetCore 3.0 助力 WPF 开发

    前言 Visual Studio 2019 已经正式发布了,DotNetCore 3.0 的正式版也指日可待.在之前的版本中,作为一名基于微软生态的传统 WPF 程序员看着隔壁同学在开发 DotNet ...

  2. 将传统 WPF 程序迁移到 DotNetCore 3.0

    介绍 由于历史原因,基于 Windows 平台存在着大量的基于 .NetFramework 开发的 WPF 和 WinForm 相关程序,如果将这些程序全部基于 DotNetCore 3.0 重写一遍 ...

  3. 使用 MSIX 打包 DotNetCore 3.0 客户端程序

    如何你希望你的 WPF 程序能够以 Windows 的保护机制保护起来,不被轻易反编译的话,那么这篇文章应该能帮到你. 介绍 MSIX 是微软于去年的 Windows 开发者日峰会 上推出的全新应用打 ...

  4. 创建或打开解决方案时提示“DotNetCore.1.0.1-SDK.1.0.0.Preview2-003131-x86“错误的解决方案

    创建或打开解决方案时提示"DotNetCore.1.0.1-SDK.1.0.0.Preview2-003131-x86"错误的解决方案 参考文章: (1)创建或打开解决方案时提示& ...

  5. 关于asp.net2.0资源文件本地化多语言版本的一些小技巧

    花了几个小时,把我的每天记帐的程序改成多语言版本的了~~~ Asp.net 2.0提供了本地化多语言版本的一些方便的特性,网上关于这个的文章已经很多了,我在此就不用多说拉,我只是说说,我在做的时候碰到 ...

  6. 安装DotNetCore.1.0.0-VS2015Tools.Preview2.exe 错误Error 0x81f40001 解决方法

    安装DotNetCore.1.0.0-VS2015Tools.Preview2.exe 错误Error 0x81f40001 解决方法 参考文章: (1)安装DotNetCore.1.0.0-VS20 ...

  7. Scratch3.0——助力新进程序员理解程序(案例一、画画的蝴蝶)

    Scratch3.0--助力新进程序员理解程序(案例一.画画的蝴蝶) 前言 一般来说,针对6-18岁的少年儿童开展的编程教育,现在,最常见的形式是线上和线下模式相结合的课外培训. 这里我用作让大朋友们 ...

  8. Scratch3.0——助力新进程序员理解程序(案例八、等差数列计算1)

    Scratch3.0--助力新进程序员理解程序(案例八.等差数列计算1) 前言 一般来说,针对6-18岁的少年儿童开展的编程教育,现在,最常见的形式是线上和线下模式相结合的课外培训. 这里我用作让大朋 ...

  9. Scratch3.0——助力新进程序员理解程序(案例九、等差数列2)

    Scratch3.0--助力新进程序员理解程序(案例九.等差数列2) 前言 一般来说,针对6-18岁的少年儿童开展的编程教育,现在,最常见的形式是线上和线下模式相结合的课外培训. 这里我用作让大朋友们 ...

最新文章

  1. Handle In-Day Changes
  2. Python常用模块之sys模块
  3. mysql 常用权限_MySQL的权限有哪些
  4. C++pair对组的创建
  5. A. And Then There Were K
  6. 多路复用IO: select、sys_select、do_select源码分析
  7. 机器学习笔记【一】- 线性回归(末):统计学推导以及局部加权线性回归算法实例
  8. 编写带界面的ActiveX控件(CAB网页控件)全过程
  9. NASM汇编教程翻译01 第一讲 Hello, World!
  10. DBVisualizer导入excel数据
  11. ​以数据科学家的眼光投资,你可能会一夜暴富
  12. 防DNS劫持教程,手动修复本地DNS教程
  13. 文科生的悲哀-斐波拉契数列
  14. (新)B站视频播放源地址获取及B站视频下载
  15. ValueError: cannot reshape array of size xxx into shape (xxx,xxx,xxx)解决方法
  16. 康耐视VisionPro
  17. HTTP请求以及接收的方式
  18. 爬虫需谨慎!那些你不知道的爬虫反爬虫套路,学起来!
  19. Spark性能调优案例-优化spark估计表大小失败 和 小表关联 走 broadcast join
  20. 如何构建一个成功的期权交易系统?

热门文章

  1. windows7黑屏修复_如何在Windows 10更新后修复黑屏
  2. 【前端基础进阶】JS-Object 功能详解
  3. C#自定义字符串压缩和解压缩源码库
  4. mt19937 -- 高质量随机数
  5. Mysql 的子查询
  6. Android6.0到底有什么不一样
  7. Tushare数据的绘图操作
  8. vim学习日志(5):vim下wimrc的配置,解决中文乱码问题
  9. 一个不成功人士的“成功之道”
  10. go方法的深入探究(7.21增补)