文章目录
- 前言
- 国际化
- 翻译Api选择
- 小牛测试
- 语言选择
- 代码逻辑
- 实体对象
- 翻译帮助类
- 导出模板
- 读取文件
- 翻译
- 测试
- 多语言测试
- 综合翻译
- 文件准备
- 测试代码
- 测试结果
- 完整代码
- 实体类
- 翻译帮助类
- 网络帮助类
- 最终效果
- 翻译前
- 翻译中
- 翻译后
- 总结
前言
为了面向更大的市场,国际化是肯定的。我想如果我开发游戏,至少要支持两种语言,英语和中文简体。
国际化
翻译Api选择
国内Api也有三种选择,百度,有道和小牛。我这里就选小牛了,比较便宜。
小牛测试
小牛翻译平台
使用PostMan测试成功
语言选择
首先,作为中文为母语,所以我至少支持三种语言。简中,繁中和英语。下面附上小牛的对应参数表
语言 | 参数 |
---|---|
简中 | zh |
繁中 | cht |
英语 | en |
德语 | de |
法语 | fr |
西班牙语 | es |
意大利语 | it |
葡萄牙语 | pt |
俄语 | ru |
日语 | ja |
韩语 | ko |
吐槽一下,写了这么多,我都快认不清这个【语】字是什么意思了。
原文选择我这里选择英语作为原文,因为这样可以顺便学一下英语。
代码逻辑
这里使用了MiniExcel
Json化方式
实体对象
public class TranslateModel
{
public TranslateModel() { }
public TranslateModel(string scene,string key,string en) {
Scene = scene;
Key = key;
EN = en;
}
public string Scene { get; set; }
public string Key { get; set; }
/// <summary>
/// 英语
/// </summary>
public string EN { get; set; }
/// <summary>
/// 简体中文
/// </summary>
public string ZH { get; set; }
/// <summary>
/// 繁体中文
/// </summary>
public string CHT { get; set; }
/// <summary>
/// 德语
/// </summary>
public string DE { get; set; }
/// <summary>
/// 法语
/// </summary>
public string FR { get; set; }
/// <summary>
/// 西班牙语
/// </summary>
public string ES { get; set; }
/// <summary>
/// 意大利语
/// </summary>
public string IT { get; set; }
/// <summary>
/// 葡萄牙语
/// </summary>
public string PT { get; set; }
/// <summary>
/// 俄语
/// </summary>
public string RU { get; set; }
/// <summary>
/// 日语
/// </summary>
public string JA { get; set; }
/// <summary>
/// 韩语
/// </summary>
public string KO { get; set; }
}
翻译帮助类
public class TranslateHelper
{
/// <summary>
/// 存放读取的数据
/// </summary>
public IEnumerable<TranslateModel> Translates { get; private set; }
/// <summary>
/// 模板路径
/// </summary>
public readonly string TemplateUrl = "Assests/translate_template.xlsx";
/// <summary>
/// 读取路径
/// </summary>
public readonly string ReadUrl = "Assests/translate_read.xlsx";
/// <summary>
/// 翻译导出路径
/// </summary>
public readonly string WriteUrl = "Assests/translate_read.xlsx";
public TranslateHelper()
{
}
}
导出模板
/// <summary>
/// 导出模板,如果文件存在则跳过
/// </summary>
public void CreateTemplate()
{
if (!File.Exists(TemplateUrl))
{
var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
var saveTemplate = new List<TranslateModel>();
saveTemplate.Add(new TranslateModel("Main", "Hello", "Hello World!"));
MiniExcel.SaveAs(TemplateUrl, saveTemplate,configuration: config);
}
}
读取文件
翻译
这里用一下我的封装
C# HttpClient Get Post简单封装
先来一个Hello world!翻译
public class TranslateHelper
{
public enum Language { zh, cht, en, de, fr, es, it, pt, ru, ja, ko }
/// <summary>
/// 存放读取的数据
/// </summary>
public IEnumerable<TranslateModel> Translates { get; private set; }
/// <summary>
/// 模板路径
/// </summary>
public const string TemplateUrl = "Assests/translate_template.xlsx";
/// <summary>
/// 读取路径
/// </summary>
public const string ReadUrl = "Assests/translate_read.xlsx";
/// <summary>
/// 翻译导出路径
/// </summary>
public const string WriteUrl = "Assests/translate_read.xlsx";
public const string API_KEY = "你的key";
public const string APPID = "你的ip";
public const string API_URL = "https://api.niutrans.com/NiuTransServer/translation";
public TranslateHelper()
{
}
/// <summary>
/// 导出模板,如果文件存在则跳过
/// </summary>
public void CreateTemplate()
{
if (!File.Exists(TemplateUrl))
{
var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
var saveTemplate = new List<TranslateModel>();
saveTemplate.Add(new TranslateModel("Main", "Hello", "Hello World!"));
MiniExcel.SaveAs(TemplateUrl, saveTemplate, configuration: config);
}
}
public void Read()
{
Translates = MiniExcel.Query<TranslateModel>(ReadUrl);
}
public async Task<string> TranslateFromEN(string en, Language language)
{
//这个是我自己封装的,你也可以用微软官方的原生httpclient
var httpHelper = new MyHttpHelper(API_URL);
var data = new
{
src_text = en,
from = "en",
to = language.ToString(),
apikey = API_KEY,
};
var res = await httpHelper.JsonHttpPost<Dictionary<string,string>>("", data, null);
var str = res["tgt_text"];
return str;
}
}
测试
static void Main(string[] args)
{
var helper = new TranslateHelper();
helper.CreateTemplate();
Console.WriteLine("开始!");
Task.Run(async () =>
{
var res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.zh);
Console.WriteLine(res);
});
Console.WriteLine("结束!");
Console.ReadKey();
}
多语言测试
Task.Run(async () =>
{
var res = "";
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.zh);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.cht);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.de);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.fr);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.es);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.it);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.pt);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.ru);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.ja);
Console.WriteLine(res);
res = await helper.TranslateFromEN("Hello world!", TranslateHelper.Language.ko);
Console.WriteLine(res);
});
综合翻译
/// <summary>
/// 读取并写入机翻结果
/// </summary>
/// <returns></returns>
public async Task ReadAndWrite()
{
if(!File.Exists(ReadUrl))
{
Console.WriteLine($"[{ReadUrl}]文件不存在,读取失败");
return;
}
else
{
Translates = MiniExcel.Query<TranslateModel>(ReadUrl).ToArray();
}
if (File.Exists(WriteUrl))
{
Console.WriteLine($"[{WriteUrl}]文件已存在,跳过翻译");
return ;
}
else
{
for(var i = 0;i< Translates.Count();i++)
{
Console.WriteLine($"翻译进度:[{i}/{Translates.Count()}]");
Translates[i] = await TranslateAllFromEN(Translates[i]);
}
//将数据保留
MiniExcel.SaveAs(WriteUrl, Translates);
}
}
/// <summary>
/// 从EN翻译全部
/// </summary>
/// <returns></returns>
public async Task<TranslateModel> TranslateAllFromEN(TranslateModel translateModel)
{
if (translateModel.EN != null && translateModel.EN != "")
{
var en = translateModel.EN;
translateModel.ZH = await TranslateFromEN(en, Language.zh);
translateModel.CHT = await TranslateFromEN(en, Language.cht);
translateModel.DE = await TranslateFromEN(en, Language.de);
translateModel.FR = await TranslateFromEN(en, Language.fr);
translateModel.ES = await TranslateFromEN(en, Language.es);
translateModel.IT = await TranslateFromEN(en, Language.it);
translateModel.PT = await TranslateFromEN(en, Language.pt);
translateModel.RU = await TranslateFromEN(en, Language.ru);
translateModel.JA = await TranslateFromEN(en, Language.ja);
translateModel.KO = await TranslateFromEN(en, Language.ko);
Console.WriteLine(JsonConvert.SerializeObject(translateModel));
}
else
{
Console.WriteLine($"Scene[{translateModel.Scene}],Key[{translateModel.Key}]的EN为空");
}
return translateModel;
}
/// <summary>
/// EN单独翻译
/// </summary>
/// <param name="en"></param>
/// <param name="language"></param>
/// <returns></returns>
public async Task<string> TranslateFromEN(string en, Language language)
{
//防止请求过快,小牛API并发有限制
await Task.Delay(100);
//Console.WriteLine(language.ToString());
var httpHelper = new MyHttpHelper(API_URL);
var data = new
{
src_text = en,
from = "en",
to = language.ToString(),
apikey = API_KEY,
};
var res = await httpHelper.JsonHttpPost<Dictionary<string,string>>("", data, null);
var str = res["tgt_text"];
return str;
}
文件准备
测试代码
Task.Run(async () =>
{
await helper.ReadAndWrite();
});
测试结果
完整代码
实体类
public class TranslateModel
{
public TranslateModel() { }
public TranslateModel(string scene,string key,string en) {
Scene = scene;
Key = key;
EN = en;
}
public string Scene { get; set; }
public string Key { get; set; }
/// <summary>
/// 英语
/// </summary>
public string EN { get; set; }
/// <summary>
/// 简体中文
/// </summary>
public string ZH { get; set; }
/// <summary>
/// 繁体中文
/// </summary>
public string CHT { get; set; }
/// <summary>
/// 德语
/// </summary>
public string DE { get; set; }
/// <summary>
/// 法语
/// </summary>
public string FR { get; set; }
/// <summary>
/// 西班牙语
/// </summary>
public string ES { get; set; }
/// <summary>
/// 意大利语
/// </summary>
public string IT { get; set; }
/// <summary>
/// 葡萄牙语
/// </summary>
public string PT { get; set; }
/// <summary>
/// 俄语
/// </summary>
public string RU { get; set; }
/// <summary>
/// 日语
/// </summary>
public string JA { get; set; }
/// <summary>
/// 韩语
/// </summary>
public string KO { get; set; }
}
翻译帮助类
public class TranslateHelper
{
public enum Language { zh, cht, en, de, fr, es, it, pt, ru, ja, ko }
/// <summary>
/// 存放读取的数据
/// </summary>
public TranslateModel[] Translates { get; private set; }
/// <summary>
/// 模板路径
/// </summary>
public const string TemplateUrl = "Assests/translate_template.xlsx";
/// <summary>
/// 读取路径
/// </summary>
public const string ReadUrl = "Assests/translate_read.xlsx";
/// <summary>
/// 翻译导出路径
/// </summary>
public const string WriteUrl = "Assests/translate_write.xlsx";
public const string API_KEY = "你的key";
public const string APPID = "你的appid";
public const string API_URL = "https://api.niutrans.com/NiuTransServer/translation";
public TranslateHelper()
{
}
/// <summary>
/// 导出模板,如果文件存在则跳过
/// </summary>
public void CreateTemplate()
{
if (!File.Exists(TemplateUrl))
{
var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
var saveTemplate = new List<TranslateModel>();
saveTemplate.Add(new TranslateModel("Main", "Hello", "Hello World!"));
MiniExcel.SaveAs(TemplateUrl, saveTemplate, configuration: config);
}
else
{
Console.WriteLine($"[{TemplateUrl}]文件已存在,跳过创建");
}
}
/// <summary>
/// 读取并写入机翻结果
/// </summary>
/// <returns></returns>
public async Task ReadAndWrite()
{
if(!File.Exists(ReadUrl))
{
Console.WriteLine($"[{ReadUrl}]文件不存在,读取失败");
return;
}
else
{
Translates = MiniExcel.Query<TranslateModel>(ReadUrl).ToArray();
}
if (File.Exists(WriteUrl))
{
Console.WriteLine($"[{WriteUrl}]文件已存在,跳过翻译");
return ;
}
else
{
for(var i = 0;i< Translates.Count();i++)
{
Console.WriteLine($"翻译进度:[{i+1}/{Translates.Count()}]");
Translates[i] = await TranslateAllFromEN(Translates[i]);
}
var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
//将数据保留
MiniExcel.SaveAs(WriteUrl, Translates,configuration:config);
}
}
/// <summary>
/// 从EN翻译全部
/// </summary>
/// <returns></returns>
public async Task<TranslateModel> TranslateAllFromEN(TranslateModel translateModel)
{
if (translateModel.EN != null && translateModel.EN != "")
{
var en = translateModel.EN;
translateModel.ZH = await TranslateFromEN(en, Language.zh);
translateModel.CHT = await TranslateFromEN(en, Language.cht);
translateModel.DE = await TranslateFromEN(en, Language.de);
translateModel.FR = await TranslateFromEN(en, Language.fr);
translateModel.ES = await TranslateFromEN(en, Language.es);
translateModel.IT = await TranslateFromEN(en, Language.it);
translateModel.PT = await TranslateFromEN(en, Language.pt);
translateModel.RU = await TranslateFromEN(en, Language.ru);
translateModel.JA = await TranslateFromEN(en, Language.ja);
translateModel.KO = await TranslateFromEN(en, Language.ko);
Console.WriteLine(JsonConvert.SerializeObject(translateModel));
}
else
{
Console.WriteLine($"Scene[{translateModel.Scene}],Key[{translateModel.Key}]的EN为空");
}
return translateModel;
}
/// <summary>
/// EN单独翻译
/// </summary>
/// <param name="en"></param>
/// <param name="language"></param>
/// <returns></returns>
public async Task<string> TranslateFromEN(string en, Language language)
{
//防止请求过快,小牛API并发有限制
await Task.Delay(100);
//Console.WriteLine(language.ToString());
var httpHelper = new MyHttpHelper(API_URL);
var data = new
{
src_text = en,
from = "en",
to = language.ToString(),
apikey = API_KEY,
};
var res = await httpHelper.JsonHttpPost<Dictionary<string,string>>("", data, null);
var str = res["tgt_text"];
return str;
}
}
网络帮助类
public class MyHttpHelper
{
private string baseUrl;
/// <summary>
/// 基础Api
/// </summary>
public string BaseUrl
{
get
{
return baseUrl;
}
set
{
baseUrl = value;
MyHttpClient = new HttpClient()
{
BaseAddress = new Uri(baseUrl)
};
}
}
public HttpClient MyHttpClient { get; set; }
public MyHttpHelper()
{
}
public MyHttpHelper(string baseUrl)
{
BaseUrl = baseUrl;
}
/// <summary>
/// 序列化返回值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="api"></param>
/// <param name="strParams"></param>
/// <returns></returns>
public async Task<T> JsonHttpGet<T>(string api, Dictionary<string, string> strParams)
{
var res = await MyHttpGet(api, strParams);
return await res.Content.ReadFromJsonAsync<T>();
}
/// <summary>
/// 序列化返回值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="api"></param>
/// <param name="value"></param>
/// <param name="strParams"></param>
/// <returns></returns>
public async Task<T> JsonHttpPost<T>(string api, object value, Dictionary<string, string> strParams)
{
var res = await MyHttpPost(api, value, strParams);
return await res.Content.ReadFromJsonAsync<T>();
}
/// <summary>
/// 序列化请求
/// </summary>
/// <param name="api"></param>
/// <param name="param"></param>
/// <returns></returns>
public async Task<HttpResponseMessage> MyHttpGet(string api, Dictionary<string, string> param)
{
string paramStr = DictionaryToParams(param);
return await MyHttpClient.GetAsync(api + paramStr);
}
/// <summary>
/// 自定义的转发功能
/// </summary>
/// <param name="api"></param>
/// <param name="dataname"></param>
/// <param name="value"></param>
/// <returns></returns>
public Task<HttpResponseMessage> MyHttpPost(string api, object value, Dictionary<string, string> strParams)
{
return MyHttpClient.PostAsync(api + DictionaryToParams(strParams), new StringContent(JsonConvert.SerializeObject(value), Encoding.UTF8, "application/json"));
}
/// <summary>
/// 字典转参数
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public string DictionaryToParams(Dictionary<string, string> param)
{
var res = "";
if (param != null)
{
var list = param.ToList();
if (list.Count != 0)
{
for (var i = 0; i < list.Count; i++)
{
if (i != 0)
{
res += "&";
}
res += $"{list[i].Key}={list[i].Value}";
}
res = "?" + res;
}
}
return res;
}
}
最终效果
翻译前
翻译中
翻译后
总结
多语言发布,这样可以让我们的游戏在更多的国家用户使用。虽然我暂时没有这个需求,但是说不定也有别的项目需要多语言的本地化接入。