当前位置:   article > 正文

WPF 本地多语言总结_wpf 多语言

wpf 多语言

去年底今年初,由于WPF项目,需要支持日本地区,要求可以切换语言。本篇文章汇总了一下,当时的调研的结果,和项目中所采用的方式。

业务背景

当时,软件主要针对的是英语国家。后来因业务需要,增加了日本地区,需要一套可切换的日语操作界面。
一方面,由于软件早期没有考虑过多语言,改造幅度比较大;另一方面,由于翻译问题,需要日本方面,可以即时修改翻译的内容。总结一下需求:

  1. 软件需全面修改,包括前端界面,后端文字,数据库配置项等;
  2. 易扩展,易修改;
  3. 调整翻译内容后,可及时展现在界面上;
  4. 希望使用 Excel 文档,来作为编辑工具;

我的调研

我在网上查找了不少资料,简单实现简单的demo,整体倾向使用,微软推荐的方法。具体查找的资料如下:

我的实现方法

参考了上面的所有方法,根据项目的需求,实现一个demo。实现起来其实蛮简单的:

  1. 创建一个多语言通用类库,这里面只包含多语言的resx文件,resx 可以包含:字符串、图像、音频、文件、其他;
    多语言通用类库

  2. 使用ResXResourceManager,来编写多语言内容,这个插件的功能很强大,有复制粘贴,排序,检索,导入导出excel等;还可以选中代码,快速添加;很多功能有待发现;
    resx资源管理插件
    resx资源管理插件2

  3. 自动生成的cs代码,具有强类型引用,不易出错;

  1. /// <summary>
  2. /// 硬件自动名称..
  3. /// </summary>
  4. public static string HW_Auto_Name {
  5. get {
  6. return ResourceManager.GetString("HW_Auto_Name", resourceCulture);
  7. }
  8. }
  9. // 使用方式
  10. string tip = ResourceText.HW_Auto_Name;
  1. 在WPF的 xaml 界面使用方式,示例;
  1. xmlns:resx="clr-namespace:LanguageResources;assembly=LanguageResources"
  2. Content="{x:Static resx:ResourceText.HW_Auto_Name}"
  1. 最后通过VS的编译,生成一个语言文件夹ja-JP里面包含一个资源dllLanguageResources.resources.dll;
  2. 如果对翻译内容进行改变,则还额外需要的操作步骤;
    使用Resgen.exe将每个文本XML资源文件编译为二进制.resources文件。输出是一组文件,这些文件的文件名与.resx或.txt文件相同,但扩展名为.resources。
  1. Visual Studio 2017,在文件路径中找到resgen.exe;
  2. %PROGRAMFILES(X86)%\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\resgen.exe
  3. //执行resgen命令,生成LanguageResources.ResourceText.ja-JP.resources
  4. resgen LanguageResources.ResourceText.ja-JP.resx
  5. //执行al命令,生成LanguageResources.resources.dll
  6. al -target:lib -embed:LanguageResources.ResourceText.ja-JP.resources -culture:ja-JP -out:LanguageResources.resources.dll

至此,所有的操作完全完成。虽然,我的方法使用微软推荐的方法,同时也有相应的辅助工具,提高了开发的效率;但是她有一个致命的缺点,是在改变翻译内容后,还需要执行额外的操作。对翻译人员的操作不友好~~。放弃!!!

项目中使用的方法

在我的方法被否决以后,心里还是有不甘心。后来项目组,安排另一位同事,开发了个Excel版本的,时隔三个月再来看,他的方法确实比我的要简单,实用。下面我就简单介绍一下:

  1. Excel 文件的读取,使用 NPOI;
  2. DependencyProperty.RegisterAttached WPF的依赖属性,通过网上查找的 DependencyProperty 资料,简单了解到它是WPF的精华所在;
  3. 在具体使用中,使用两种方式:1、根据Key值来获取翻译内容;2、根据完整英文内容,获取对应的翻译内容;

具体的代码,简化如下:

  1. public class LanguageManager
  2. {
  3. public bool IsLangOut { get; set; }
  4. public string Language { get; set; }
  5. private string langFile;
  6. private static LanguageManager _Instance;
  7. private Dictionary<string, LanguageObject> StrMap;
  8. public static LanguageManager Instance
  9. {
  10. get { return _Instance == null ? _Instance = new LanguageManager() : _Instance; }
  11. }
  12. private LanguageManager()
  13. {
  14. IsLangOut = false;
  15. Language = "en_US";
  16. langFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "LanguageError.log");
  17. }
  18. public bool Load(Func<string, Dictionary<string, LanguageObject>> LoadFile)
  19. {
  20. StrMap = LoadFile?.Invoke(Language);
  21. if (StrMap == null || StrMap.Count == 0) return false;
  22. else return true;
  23. }
  24. public string GetTranslateStr(string key)
  25. {
  26. if (string.IsNullOrEmpty(key) || StrMap == null) return string.Empty;
  27. if (StrMap.ContainsKey(key))
  28. {
  29. return StrMap[key].Trans;
  30. }
  31. else
  32. {
  33. Write2File($"no key: [{key}]\n");
  34. return key;
  35. }
  36. }
  37. public string TranslateStr(string text)
  38. {
  39. if (Language == "en-US" || StrMap == null) return text;
  40. var lang = StrMap.Values.FirstOrDefault(p => p.English.Trim() == text.Trim());
  41. if (lang == null)
  42. {
  43. Write2File($"can't find value: [{text}]\n");
  44. return text;
  45. }
  46. else
  47. return lang.Trans;
  48. }
  49. public void Write2File(string context)
  50. {
  51. if (!IsLangOut) return;
  52. System.IO.File.AppendAllText(langFile, context, System.Text.Encoding.UTF8);
  53. }
  54. }

   基础类 LanguageObject

  1. public class LanguageObject
  2. {
  3. public string English { get; set; }
  4. public string Trans { get; set; }
  5. }

 

  1. public class LanguageBehavior
  2. {
  3. public static readonly DependencyProperty KeyProperty =
  4. DependencyProperty.RegisterAttached("Key",
  5. typeof(string), typeof(LanguageBehavior),
  6. new FrameworkPropertyMetadata(string.Empty, OnKeyChanged));
  7. private static void OnKeyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
  8. {
  9. Update(sender, e.NewValue as string);
  10. }
  11. public static void SetKey(DependencyObject dp, string value)
  12. {
  13. dp.SetValue(KeyProperty, value);
  14. }
  15. public static string GetKey(DependencyObject dp)
  16. {
  17. return dp.GetValue(KeyProperty) as string;
  18. }
  19. public static readonly DependencyProperty ToolTipProperty =
  20. DependencyProperty.RegisterAttached("ToolTip",
  21. typeof(string), typeof(LanguageBehavior),
  22. new FrameworkPropertyMetadata(string.Empty, OnToolTipChanged));
  23. private static void OnToolTipChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
  24. {
  25. UpdateToolTip(sender, e.NewValue as string);
  26. }
  27. public static void SetToolTip(DependencyObject dp, string value)
  28. {
  29. dp.SetValue(ToolTipProperty, value);
  30. }
  31. public static string GetToolTip(DependencyObject dp)
  32. {
  33. return dp.GetValue(ToolTipProperty) as string;
  34. }
  35. private static void Update(DependencyObject sender, string key)
  36. {
  37. if (sender is TabItem)
  38. (sender as TabItem).Header = LanguageManager.Instance.GetTranslateStr(key);
  39. else if (sender is Label)
  40. (sender as Label).Content = LanguageManager.Instance.GetTranslateStr(key);
  41. else if (sender is ContentControl)
  42. (sender as ContentControl).Content = LanguageManager.Instance.GetTranslateStr(key);
  43. else if (sender is TextBlock)
  44. (sender as TextBlock).Text = LanguageManager.Instance.GetTranslateStr(key);
  45. else if (sender is Run)
  46. (sender as Run).Text = LanguageManager.Instance.GetTranslateStr(key);
  47. else if (sender is GridViewColumn)
  48. (sender as GridViewColumn).Header = LanguageManager.Instance.GetTranslateStr(key);
  49. }
  50. private static void UpdateToolTip(DependencyObject sender, string key)
  51. {
  52. if (!(sender is FrameworkElement)) return;
  53. (sender as FrameworkElement).ToolTip = LanguageManager.Instance.GetTranslateStr(key);
  54. }
  55. }
  56. 在 XAML 的使用示例:
  57. <Button x:Name="btn1" Height="40" Lang:LanguageBehavior.Key="K00259" />
  58. <Button x:Name="btn2" Width="32" Height="32" Lang:LanguageBehavior.ToolTip="K00189" />
  59. 在 cs 的使用示例:
  60. this.textError.Text = LanguageManager.Instance.GetTranslateStr("K00204");
  61. this.textError.Text = LanguageManager.Instance.TranslateStr("Can not connect server");

总结

在项目运行至今,很明显第二种方法的好,测试人员,运维人员,在可以完全不接触代码的情况下。只操作Excel 来实现文件内容的翻译,并且“实时”的反应到软件上。
而我固执己见的“微软官方推荐方法”,并不适用于项目;好比是纸上谈兵的赵括,真的是越来越为当时的“倔强”,感到羞愧。。。


我们生而自由
却被后台种种
无形枷锁束缚

 

本文转自: 博客园-顺风椰子皮  原文地址

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号