<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      概覽

      隨著我們的應(yīng)用程序越來(lái)越受歡迎,我們的下一步將要開發(fā)多語(yǔ)言功能。方便越來(lái)越多的國(guó)家使用我們中國(guó)的應(yīng)用程序,
      基于 WPF 本地化,我們很多時(shí)候使用的是系統(tǒng)資源文件,可是動(dòng)態(tài)切換本地化,就比較麻煩了。
      有沒有一種方法既可以適用系統(tǒng)的資源文件,又能方便快捷的切換本地化呢?

      實(shí)現(xiàn)思路

      現(xiàn)在我們將要實(shí)現(xiàn)的是基于 DotNetCore 3.0 以上版本 and WPF 桌面應(yīng)用程序模塊化的多語(yǔ)言功能。
      動(dòng)態(tài)切換多語(yǔ)言思路:

      * 把所有模塊的資源文件添加到字典集合。
      * 將資源文件里的key,綁定到前臺(tái)。
      * 通過(guò)通知更改 CurrentCulture 多語(yǔ)言來(lái)使用改變的語(yǔ)言文件里的key。
      * 通過(guò)綁定 Binding 拼接Path 在輸出。
      動(dòng)態(tài)切換

      我們先來(lái)看實(shí)現(xiàn)結(jié)果


      * 第一行是我們的主程序的數(shù)據(jù)展示,用于業(yè)務(wù)中的本地化

      * 第二行是我們業(yè)務(wù)模塊A的數(shù)據(jù)展示

      * 第三行是我們業(yè)務(wù)模塊B的數(shù)據(jù)展示
      來(lái)看一下xaml展示


      通過(guò)ComboBox選擇來(lái)切換語(yǔ)言


      搭建模擬業(yè)務(wù)項(xiàng)目

      創(chuàng)建一個(gè)WPF App(.NET Core)應(yīng)用程序


      創(chuàng)建完成后,我們需要引入業(yè)務(wù)A模塊及業(yè)務(wù)B模塊和業(yè)務(wù)幫助模塊

      PS:根據(jù)自己的業(yè)務(wù)需要來(lái)完成項(xiàng)目的搭建。本教程完全適配多語(yǔ)言功能。

      使用ResX資源文件

      在各個(gè)模塊里添加Strings 文件夾用來(lái)包含 各個(gè)國(guó)家和地區(qū)的語(yǔ)言文件。


      多語(yǔ)言可以參考:
      https://github.com/UnRunDeaD/WPF---Localization/blob/master/ComboListLanguages.txt

      <https://github.com/UnRunDeaD/WPF---Localization/blob/master/ComboListLanguages.txt>

      資源文件可以放在任意模塊內(nèi),比如業(yè)務(wù)模塊A ,主程序,底層業(yè)務(wù),控件工具集等

      創(chuàng)建各個(gè)業(yè)務(wù)模塊資源文件

      Strings文件夾可以任意命名
      SR資源文件可以任意命名


      幫助類

      封裝到底層供各個(gè)模塊調(diào)用
      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; // string.Empty/null indicates that all properties have changed
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty)); } }
      } // WPF bindings register PropertyChanged event if the object supports it and
      update themselves when it is raised 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); // does
      this control have a "Translation.ResourceManager" attached property with a set
      value? if (localValue != DependencyProperty.UnsetValue) { if (localValue is
      ResourceManager resourceManager) {
      TranslationSource.Instance.AddResourceManager(resourceManager); return
      resourceManager; } } } return null; } public override object
      ProvideValue(IServiceProvider serviceProvider) { // targetObject is the control
      that is using the LocExtension object targetObject = (serviceProvider as
      IProvideValueTarget)?.TargetObject; if (targetObject?.GetType().Name ==
      "SharedDp") // is extension used in a control template? return targetObject; //
      required for template re-binding string baseName =
      GetResourceManager(targetObject)?.BaseName ?? string.Empty; if
      (string.IsNullOrEmpty(baseName)) { // rootObject is the root control of the
      visual tree (the top parent of targetObject) object rootObject =
      (serviceProvider as IRootObjectProvider)?.RootObject; baseName =
      GetResourceManager(rootObject)?.BaseName ?? string.Empty; } if
      (string.IsNullOrEmpty(baseName)) // template re-binding { 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); } }
      前臺(tái)綁定


      //引用業(yè)務(wù)模塊 xmlns:ext="clr-namespace:WpfUtil.Extension;assembly=WpfUtil" //
      引用剛才你命名的文件夾名字 xmlns:resx="clr-namespace:ModuleA.Strings" //
      每個(gè)模塊通過(guò)幫助類,將當(dāng)前模塊的資源類, // 加載到資源管理集合里面用于分配每個(gè)鍵值 // 引用剛才你命名的資源文件名字 -> SR
      ext:Translation.ResourceManager="{x:Static resx:SR.ResourceManager}"
      顯示文字
      //讀取資源文件里的鍵值 <Label Content="{ext:Loc Test}" FontSize="21" />
      后臺(tái)實(shí)現(xiàn)

      根據(jù)業(yè)務(wù)的需要,我們?cè)诮缑嫔蠠o(wú)法適用靜態(tài)文字顯示的,一般通過(guò)后臺(tái)代碼來(lái)完成,對(duì)于 code-behind 的變量使用,同樣可以應(yīng)用于資源字典。
      比如在業(yè)余模塊代碼段里的模擬實(shí)現(xiàn)
      // SR 是當(dāng)前業(yè)務(wù)模塊的資源文件類,管理當(dāng)前模塊的資源字符串。 // 根據(jù)不同的 `CurrentCulture` 選擇相對(duì)應(yīng)的本地化 Message
      =
      string.Format(SR.ResourceManager.GetString("Message",Thread.CurrentThread.CurrentUICulture),System.DateTime.Now);
      PS: 歡迎各位大佬慷慨指點(diǎn),有不足之處,請(qǐng)指出!有疑問,請(qǐng)指出,喜歡它,請(qǐng)支持!

      下載地址

      https://github.com/androllen/WpfNetCoreLocalization
      <https://github.com/androllen/WpfNetCoreLocalization>

      相關(guān)鏈接


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

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

      https://codinginfinity.me/post/2015-05-10/localization_of_a_wpf_app_the_simple_approach

      <https://codinginfinity.me/post/2015-05-10/localization_of_a_wpf_app_the_simple_approach>

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          天天曰天天干天天射Av | av91肉丝一区二区电影 | 啊灬啊灬啊灬快灬高潮了小视频 | 狠狠爱无码| 天天操官网 | 精品日韩人妻一区二区三中文字幕 | 国产边打电话边被躁说在跑步 | 四虎最新网站 | 翔田千里 無碼破解 | 91嫩|婷婷丨入口图片 |