C# 基于Json文件的多语言翻译功能简单实现

踏上自动化的不归路 2019-09-09 05:52:14
在网上查阅很多方法,Json配置是亲测思路相对简单,代码量少较易实现的的方法

大致思路:
将Json文件系列化储存在Dictionary中,再通过遍历指定控件及其子控件进行匹配替换。
注意:特殊需求(如:String中只局部翻译)以及个别控件(如:ToolStrip)需要自行添加处理方法,后续会详细讲解怎样去遍历特殊控件。

具体实现及演示:
1、准备工作:
1.1 添加Json配置,网上有很多关于Json配置相关的文章不做详细讲解

C#使用json
点击工具 - NuGet包管理器 - 程序包管理控制台,输入下面命令:
Install-Package Newtonsoft.Json
即可使用Newtonsoft.Json 包进行json操作
PM> Install-Package Newtonsoft.Json



1.2 对应的Json文件的编辑 :key翻译为value
英译中 Json配置
{
"Test":"测试",
"Language":"语言",
"Set":"设置",
"Chinese (default)":"中文(默认)",
"English":"英文"
}

中译英 Json配置
{
"测试":"Test",
"语言":"Language",
"设置":"Set",
"中文(默认)": "Chinese (default)",
"英文":"English",
"英语":"English"
}


1.3 向窗体放置各种常用控件以及对其相应文本进行编辑如图1



2、自定义翻译类库

using Newtonsoft.Json; //Json文件序列化
using System.Windows.Forms; //控件遍历所需
using System.Text.RegularExpressions; //String处理

namespace Interpret
{
public class InterpretBase
{
//下文代码
}
}

2.1 现有的资源加载方法
 
//定义字典用于储存Json配置文件资源
static Dictionary<string, string> resources = new Dictionary<string, string>();

/// <summary>
/// 当前项目文件夹Debug\Language\参数文件夹
/// </summary>
/// <param name="language">配置文件所在文件夹名</param>
public static void LoadLanguage(string language = "")
{
if (string.IsNullOrEmpty(language))
{
language = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
}

resources = new Dictionary<string, string>();

string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("Language/{0}", language));
if (Directory.Exists(dir))
{
var jaonFile = Directory.GetFiles(dir, "*.json", SearchOption.AllDirectories);
foreach (string file in jaonFile)
{
LoadFile(file);
}
}
}

/// <summary>
/// 配置文件加载
/// </summary>
/// <param name="path">配置文件绝对路径(包括文件本身)</param>
public static void LoadFile(string path)
{
var content = File.ReadAllText(path, Encoding.UTF8);
if (!string.IsNullOrEmpty(content))
{
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(content);
foreach (string key in dict.Keys)
{

if (!resources.ContainsKey(key))
{
resources.Add(key, dict[key]);
}
else
resources[key] = dict[key];
}
}
}



2.2 普通控件的遍历(因为涉及其他相关 不能一一列举控件遍历,这里按Combox遍历,其他控件思路也是一样的


/// <summary>
/// 遍历翻译 窗体或控件及其子控件
/// </summary>
/// <param name="control">需要翻译的控件或窗体</param>
public static void InitLanguage(Control control)
{
SetControlLanguage(control);
foreach (Control ctrl in control.Controls)
{
InitLanguage(ctrl);
}

//工具栏或者菜单动态构建窗体或者控件的时候,重新对子控件进行处理
control.ControlAdded += (sender, e) =>
{
InitLanguage(e.Control);
};
}

/// <summary>
/// 控件及子控件翻译
/// </summary>
/// <param name="control">需要翻译的控件</param>
public static void SetControlLanguage(Control control)
{
if (control is ComboBox)
{
ComboBox combox = control as ComboBox;
string[] NewItems = new string[combox.Items.Count];
for (int i = 0; i < combox.Items.Count; i++)
{
if (resources.ContainsKey(combox.Items[i].ToString()))
{
NewItems[i] = resources[combox.Items[i].ToString()];
}
else
NewItems[i] = combox.Items[i].ToString();
}

combox.Text = (resources.ContainsKey(combox.Text)) ? resources[combox.Text] : combox.Text;

combox.Items.Clear();
combox.Items.AddRange(NewItems);
}
//control is 其他控件或者特殊控件 如:TreeView
else if (control is TreeView)
{
//TreeView treeView = control as TreeView;
//if (treeView.Nodes !=null)
//{
//TreeViewNodes(treeView.Nodes);
//}
}
else
{
control.Text = (resources.ContainsKey(control.Text)) ? resources[control.Text] : control.Text;
}
}



2.3 特殊控件的遍历思路(思路基本能满足绝大多数控件,由于详细涉及其他不能完整上传 深表歉意)

特殊控件的遍历思路其实跟普通控件的遍历是一样的 只是需要根据特殊控件不同情况去遍历的特殊属性进行判断翻译就行了(按TreeView为列讲解
注:特殊控件不知道该遍历什么属性时可以去 InitializeComponent();窗体设计器生成的代码里查找 如图下雷同




public static void TreeViewNodes(TreeNodeCollection Nodes)
{
for (int i = 0; i < Nodes.Count; i++)
{
if (Nodes[i].Text != null)
Nodes[i].Text = (resources.ContainsKey(Nodes[i].Text)) ?
resources[Nodes[i].Text] : Nodes[i].Text;

if (Nodes[i].Nodes != null)
{
TreeViewNodes(Nodes[i].Nodes);
}
}
}


2.4 添加特殊方法 供后文用
        
/// <summary>
/// 局部匹配翻译,不存在则不翻译
/// </summary>
/// <param name="text">需要翻译的正则公式</param>
public static void PartInterpret(ref string text)
{
if (resources.Keys == null && resources.Keys.Count == 0)
{
MessageBox.Show("未添加资源文件,请及时确认或与工作人员联系", "提示!!");
return;
}
foreach (var item in resources)
{
if (text.Contains(item.Key))
{
text = text.Replace(item.Key, item.Value);
}
}
}




3 调用方式及特殊情况

using IPret = Interpret.InterpretBase;//添加引用


string lang,oldLang;
//语言设置 自行设置
private void button_Click(object sender, EventArgs e)
{
oldLang = lang;//用于判断当前语言是否与所需要语言一致 ,避免
lang = comboBox1.Text.ToString();//需要设置的语言
switch (lang)
{
case "中文(默认)":
case "Chinese (default)":
lang = "zh-CN";
break;

case "英文":
case "English":
lang = "en-US";
break;

default:
lang = "zh-CN";
break;
}

if (oldLang != lang)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);

IPret.LoadLanguage(lang);
IPret.InitLanguage(contextMenuStrip1);
IPret.InitLanguage(this);

#region ***********局部特殊内容翻译************
string s = label_Test.Text;
IPret.PartInterpret(ref s);
label_Test.Text = s;
oldLang = lang;
#endregion
}
}


实际效果图:

翻译前


翻译后



感谢阅览,第一次发文 若有不足之处,还望之处
...全文
399 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
秋的红果实 2019-09-10
  • 打赏
  • 举报
回复
感谢分享
OrdinaryCoder 2019-09-10
  • 打赏
  • 举报
回复
it_gz_xi 2019-09-10
  • 打赏
  • 举报
回复
wilson1966 2019-09-10
  • 打赏
  • 举报
回复
难得奇文,赞
  • 打赏
  • 举报
回复
引用 1 楼 github_36000833的回复:
[quote=引用 楼主 踏上自动化的不归路 的回复:] ... 感谢阅览,第一次发文 若有不足之处,还望之处
鼓励并赞一个。[/quote] 谢谢 emmmmm
  • 打赏
  • 举报
回复
引用 3 楼 github_36000833的回复:

        public static string PartInterpret(string text)  // 一般不用ref string,而是返回string
        {
            ...
            foreach (var item in resources)
            {
                if (text.Contains(item.Key))
                {
                    text = text.Replace(item.Key, item.Value);
                }
            }
            return text; // 一个函数,明确的输入输出,有利于阅读。
        }
受教了 个人习惯问题 省几行代码
github_36000833 2019-09-09
  • 打赏
  • 举报
回复

        public static string PartInterpret(string text)  // 一般不用ref string,而是返回string
        {
            ...
            foreach (var item in resources)
            {
                if (text.Contains(item.Key))
                {
                    text = text.Replace(item.Key, item.Value);
                }
            }
            return text; // 一个函数,明确的输入输出,有利于阅读。
        }
  • 打赏
  • 举报
回复
github_36000833 2019-09-09
  • 打赏
  • 举报
回复
引用 楼主 踏上自动化的不归路 的回复:
... 感谢阅览,第一次发文 若有不足之处,还望之处
鼓励并赞一个。

110,561

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧