RESX 翻译工具






4.64/5 (8投票s)
一个用于本地化 .NET 项目的 C# 工具。
引言
虽然英语是一种国际语言,但许多人更喜欢使用具有本地语言界面的软件。因此,如果您希望您的软件在不同国家/地区的人们中非常受欢迎,您需要将用户界面翻译成尽可能多的语言。但在这里应该提到,软件本地化是一项艰巨的工作。这个 RESX 翻译工具有助于避免陷入困境并自动化一些操作。
该工具基于 C# 中的翻译 Web 服务,作者 Matthew Brealey,以及 用于多语言支持的 RESX 到 XLS 转换,作者 Marco Roello。
背景
有很多多语言翻译 Web 服务,例如 Google、Babelfish、Yandex 等。当然,计算机翻译不如人工翻译好,但它可以帮助加快本地化速度。
代码
翻译器执行以下操作:
- 生成发送到翻译 Web 服务 (Google) 的 POST 请求
- 接收来自 Web 服务的可读响应
- 使用正则表达式解析响应
- 返回翻译
函数 Translate
实现这些操作
public string Translate(string text, TranslateDir dir)
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(TranslateUrl);
// Encode the text to be translated
string postSourceData = GetPostSourceData(text, dir);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postSourceData.Length;
request.UserAgent = "Mozilla/4.0 (compatible; " +
"MSIE 6.0; Windows NT 5.1)";
HttpWebResponse response;
try
{
using (Stream writeStream = request.GetRequestStream())
{
byte[] bytes = Encoding.UTF8.GetBytes(postSourceData);
writeStream.Write(bytes, 0, bytes.Length);
writeStream.Close();
}
response = (HttpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
return ex.Message;
}
StreamReader readStream =
new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string page = readStream.ReadToEnd();
response.Close();
Regex reg = new Regex(RegexpResult, RegexOptions.IgnoreCase);
Match m = reg.Match(page);
string s;
if (m.Success)
{
s = m.Result("${text}");
}
else s = "regexp error";
return s;
}
protected override string RegexpResult
{
get { return @"<div[^>]+id=result_box[^>]+" +
@">(?<text>[^>]+)</div>"; }
}
函数 GetPostSourceData
生成用于发布请求的主体,该主体将文本和语言选项传递给 Google 翻译引擎。Google 的响应是可读的,并且翻译被放入 id
等于 result_box
的 div 中。
DataSet
包含两个表:Resx
和 ResxLocalized
。这些表用从加载的 *.resx 文件中读取的数据填充。函数 TranslateDataSet
用翻译后的值填充 ResxLocalized
表。为了避免由 Web 服务请求引起的额外延迟,此函数仅填充未填充的单元格。
首先,使用 LINQ 将所有未填充的记录选择到枚举 query
中。然后,查找是否有任何值等于当前值并且已经被翻译。否则,将翻译请求发送到 Google 翻译 Web 服务。
private void TranslateDataSet(ResxData rd)
{
GoogleTranslator gt = new GoogleTranslator();
DataTable resxs = rd.Resx;
DataTable resxlocs = rd.ResxLocalized;
int count = 0;
int amount;
var query =
from resx in resxs.AsEnumerable()
join resxloc in resxlocs.AsEnumerable()
on resx.Field<int32 >("ID") equals
resxloc.Field<int32 >("ParentID")
where resxloc.Field<string >("Value") == null ||
resxloc.Field<string >("Value") == ""
select new
{
Value = resx.Field<string >("Value"),
Culture = resxloc.Field<string >("Culture"),
Translation = resxloc.Field<string >("Value"),
LocID = resxloc.Field<int32 >("ID")
};
string translation;
this.BeginInvoke((MethodInvoker)delegate()
{ progressBar1.Maximum = query.Count() + 1; progressBar1.Value = 1; });
if (!query.Any())
{
this.BeginInvoke((MethodInvoker)delegate()
{ words.Text = "0 of " + query.Count().ToString(); });
}
amount = query.Count();
foreach (var record in query)
{
var enumer = query.Where(r => r.Value == record.Value &&
r.Translation != "" &&
r.Translation != null &&
r.Culture == record.Culture);
count++;
this.BeginInvoke((MethodInvoker)delegate()
{ words.Text = count.ToString() + " of " + amount.ToString(); });
if (enumer.Any())
{
translation = enumer.First().Translation;
}
else
{
translation = gt.Translate(record.Value,
new TranslateDir("auto", record.Culture.Substring(0, 2)));
}
this.BeginInvoke((MethodInvoker) delegate() { progressBar1.Value++; });
resxlocs.Rows.Find(record.LocID).SetField<string >("Value", translation);
}
}
关注点
在 C# 中处理 Excel 文件有几种方法:
- 早期绑定 COM
- 后期绑定 COM
- 使用 OLE DB 提供程序
只有最后一种方法不需要安装 Excel。以下代码显示了如何在 Excel 工作表中获取和设置值:
private void SetCell(int row, int col, OleDbConnection con, string value)
{
string c = Convert.ToChar((Convert.ToInt16('A') + col - 1)).ToString();
string r = row.ToString();
OleDbCommand cmd = new OleDbCommand("UPDATE [Localize$" + c + r + ":" +
c + r + "] SET F1 = \"" + value + "\"", con);
cmd.ExecuteNonQuery();
}
private string GetCell(int row, int col, OleDbConnection con)
{
string c = Convert.ToChar((Convert.ToInt16('A') + col - 1)).ToString();
string r = row.ToString();
OleDbCommand cmd = new OleDbCommand("SELECT * FROM [Localize$" +
c + r + ":" + c + r + "]", con);
object ret = cmd.ExecuteScalar();
if (ret == DBNull.Value) return null; else return (string)ret;
}
建议
如果有人可以贡献并实现其他翻译器的接口并发布源代码,我将更新文章并包含它们。