Legato Systems MC文件的翻译
Legato Systems https://legato.io/
An open source Linux-based embedded platform designed to simplify connected IoT application development
一个基于Linux的开源嵌入式平台,旨在简化联网物联网应用程序的开发
这个系统一般是制作Linux驱动用的,导出的文件是*.mc
文件
这个文件格式比较特殊 还有一定的容错,并不能被翻译软件 Trados直接支持,本文给出一个*.mc
转*.xml
的思路,通过转换为XML进行翻译,翻译后再写回MC
首先MC的文件结构
MC文件分为文件头和文件体两部分,文件本身设计上支持多语言,采用Unicode或UTF-8编码
;//
;// Copyright (C) 1994 - 2004 Legato Systems, Inc.
;// All rights reserved.
;//
;//
;//
;//
MessageIdTypedef = NTSTATUS
;// SeverityNames = (name=number[:name])
;// FacilityNames = (name=number[:name])
;// LanguageNames = (name=number:filename)
;//LanguageNames = (French=2:MSG00002)
SeverityNames=(Success=0x0:SUCCESS
Informational=0x1:INFO
Warning=0x2:WARNING
Severe=0x3:SEVERE
)
LanguageNames = (
English=1033:MSG1033
Chinese=2052:MSG2052
French=1036:MSG1036
Korean=1042:MSG1042
Japanese=1041:MSG1041
German=1031:MSG1031
Russian=1049:MSG1049
Spanish=2058:MSG2058
Italian=1040:MSG1040
Portuguese=1046:MSG1046
)
FacilityNames=(
System=0x0FF
Exception=0xFFE
Application=0x000
General=0x100
Framework=0x200
Resource=0x300
Module=0x400
AtmosFsDriver=0x0FFD:FAV_ATMOS_FS_DRIVER
)
其中;//
开头的行是注释行
主体采用类似INI的ID=内容
格式
SeverityNames 是一段无关的内容不需要翻译
LanguageNames 是语言名的预定义
FacilityNames 是此文件相关的具体说明
总之文件头是不需要翻译的
我这批MC文件都是来自一个系统,格式统一
因此我设置
public const int preservedHeaderCount = 42;
在循环中直接跳过
while (sr.Peek() >= 0)
{
linecounter++;
line = sr.ReadLine();
if (linecounter > preservedHeaderCount)
{
...
}
}
文件体部分
MessageId=0
Severity=Success
Facility=Application
SymbolicName=MSG_NO_ERROR
Language=English
No Error
.
; // this first set of messages are the Event Categories
MessageId=
Severity=Informational
SymbolicName=MSG_TCP_IP_BUF_SIZE_REDUCED_BY_TIMEOUT
Language=English
The TcpIp Buffer size was reduced due to a timeout. Was %1 is now %2.
Description
The Tcp Ip buffer size was automatically reduced due to a communications timeout.
Resolution
None required.
.
MessageId=
Severity=Success
SymbolicName=MSG_CAT_SERVER
Language=English
Server
.
文件体由多个统一规格的小单元组成
每个单元包含六个部分
- MessageId=
- Facility=
可选 - Severity=
- SymbolicName=
此为唯一值 - Language=
原文的值为English翻译后的应设置为文件头中定义的语言名 例如Russian - 待翻译的正文部分
正文部分存在多行情况,需要保留换行符 - .
独自成一行的一个句点.
标志单元结束
第六个部分是可容错的,有的时候没有这个部分
可能存在注释行
;//
开头的行是注释行
设计一个类通过泛型方式存取这种单元
public class item
{
public string MessageId { get; set; }
public string Severity { get; set; }
public string Facility { get; set; } //Optional
public string SymbolicName { get; set; }
public LanguageNames Language { get; set; }
public string Text { get; set; }
public bool isComments { get; set; }
}
MC转XML
MC转XML采用从上到下的读写方式
逻辑图:
代码示例
StreamReader sr = new StreamReader(file, Encoding.Unicode, true);
string line = string.Empty;
bool isStart = false;
bool isFirstLine = false;
string text = string.Empty;
Match mMessageId = null;
Match mSeverity = null;
Match mFacility = null;
Match mSymbolicName = null;
Match mLanguage = null;
int linecounter = 0;
while (sr.Peek() >= 0)
{
linecounter++;
line = sr.ReadLine();
if (linecounter > preservedHeaderCount)
{
if (regMessageId.IsMatch(line) && isStart == false)
{
Console.Write(".");
isStart = true;
item i = new item();
i.isComments = false;
mMessageId = regMessageId.Match(line);
i.MessageId = mMessageId.Groups["value"].Value;
line = sr.ReadLine();
mSeverity = regSeverity.Match(line);
i.Severity = mSeverity.Groups["value"].Value;
line = sr.ReadLine();
if (regFacility.IsMatch(line))
{
mFacility = regFacility.Match(line);
i.Facility = mFacility.Groups["value"].Value;
line = sr.ReadLine();
mSymbolicName = regSymbolicName.Match(line);
i.SymbolicName = mSymbolicName.Groups["value"].Value;
line = sr.ReadLine();
while (line == "")
{
line = sr.ReadLine();
}
mLanguage = regLanguage.Match(line);
i.Language = (LanguageNames)Enum.Parse(typeof(LanguageNames), mLanguage.Groups["value"].Value);
isFirstLine = true;
line = sr.ReadLine();
while (line != ".")
{
if (isFirstLine)
{
text = line;
isFirstLine = false;
}
else
{
text = text + "\r\n" + line;
}
line = sr.ReadLine();
}
isFirstLine = false;
isStart = false;
i.Text = text;
items.Add(i);
text = string.Empty;
}
else if (regSymbolicName.IsMatch(line))
{
mSymbolicName = regSymbolicName.Match(line);
i.SymbolicName = mSymbolicName.Groups["value"].Value;
line = sr.ReadLine();
while (line == "")
{
line = sr.ReadLine();
}
mLanguage = regLanguage.Match(line);
i.Language = (LanguageNames)Enum.Parse(typeof(LanguageNames), mLanguage.Groups["value"].Value);
isFirstLine = true;
line = sr.ReadLine();
while (line != ".")
{
if (isFirstLine)
{
text = line;
isFirstLine = false;
}
else
{
text = text + "\r\n" + line;
}
line = sr.ReadLine();
}
isFirstLine = false;
isStart = false;
i.Text = text;
items.Add(i);
text = string.Empty;
}
}
}
sr.Close();
然后输出XML,例如
<item isComments="no">
<Facility>Application</Facility>
<MessageId>0</MessageId>
<Severity>Success</Severity>
<Language>English</Language>
<Text SymbolicName="MSG_NO_ERROR"><![CDATA[No Error]]></Text>
</item>
<item isComments="yes">
<Comment><![CDATA[; // this first set of messages are the Event Categories]]></Comment>
</item>
<item isComments="no">
<MessageId>
</MessageId>
<Severity>Informational</Severity>
<Language>English</Language>
<Text SymbolicName="MSG_TCP_IP_BUF_SIZE_REDUCED_BY_TIMEOUT"><![CDATA[The TcpIp Buffer size was reduced due to a timeout. Was %1 is now %2.
Description
The Tcp Ip buffer size was automatically reduced due to a communications timeout.
Resolution
None required.]]></Text>
</item>
<item isComments="no">
<MessageId>
</MessageId>
<Severity>Success</Severity>
<Language>English</Language>
<Text SymbolicName="MSG_CAT_SERVER"><![CDATA[Server]]></Text>
</item>
方法如下
StreamWriter sw = new StreamWriter(file + ".XML", false, Encoding.Unicode);
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "Unicode", string.Empty);
doc.AppendChild(dec);
XmlElement root = doc.CreateElement("resources");
for (int i = 0; i < items.Count; i++)
{
if (items[i].isComments)
{
XmlElement elem_item = doc.CreateElement("item");
XmlAttribute AttComments = doc.CreateAttribute("isComments");
AttComments.Value = "yes";
elem_item.Attributes.Append(AttComments);
XmlElement elem_Text = doc.CreateElement("Comment");
XmlCDataSection cdata = doc.CreateCDataSection(items[i].Text);
elem_Text.AppendChild(cdata);
elem_item.AppendChild(elem_Text);
root.AppendChild(elem_item);
}
else
{
XmlElement elem_item = doc.CreateElement("item");
XmlAttribute AttComments = doc.CreateAttribute("isComments");
AttComments.Value = "no";
elem_item.Attributes.Append(AttComments);
XmlElement elem_MessageId = doc.CreateElement("MessageId");
elem_MessageId.InnerText = items[i].MessageId;
XmlElement elem_Severity = doc.CreateElement("Severity");
elem_Severity.InnerText = items[i].Severity;
if (items[i].Facility != null)
{
XmlElement elem_Facility = doc.CreateElement("Facility");
elem_Facility.InnerText = items[i].Facility;
elem_item.AppendChild(elem_Facility);
}
//XmlElement elem_SymbolicName = doc.CreateElement("SymbolicName");
//elem_SymbolicName.InnerText = items[i].SymbolicName;
XmlElement elem_Language = doc.CreateElement("Language");
elem_Language.InnerText = Enum.GetName(typeof(LanguageNames), items[i].Language);
XmlElement elem_Text = doc.CreateElement("Text");
XmlCDataSection cdata = doc.CreateCDataSection(items[i].Text);
elem_Text.AppendChild(cdata);
XmlAttribute attSymbolicName = doc.CreateAttribute("SymbolicName");
attSymbolicName.Value = items[i].SymbolicName;
elem_Text.Attributes.Append(attSymbolicName);
elem_item.AppendChild(elem_MessageId);
elem_item.AppendChild(elem_Severity);
//elem_item.AppendChild(elem_SymbolicName);
elem_item.AppendChild(elem_Language);
elem_item.AppendChild(elem_Text);
root.AppendChild(elem_item);
}
}
doc.AppendChild(root);
doc.Save(sw);
sw.Close();
最后翻译完成xml转回MC
StreamReader sr = new StreamReader(file, Encoding.Unicode, true);
StreamWriter sw = new StreamWriter(file+(".")+Enum.GetName(typeof(LanguageNames), language), false, Encoding.Unicode);
XmlDocument doc = new XmlDocument();
doc.Load(sr);
XmlElement root = doc.DocumentElement;
XmlNodeList itemsNode = root.SelectNodes("item");
XmlNode ndMessageId=null;
XmlNode ndSeverity=null;
XmlNode ndFacility=null;
//XmlNode ndSymbolicName=null;
XmlNode ndLanguage=null;
XmlNode ndText=null;
XmlCDataSection cdata=null;
foreach(XmlNode itemNode in itemsNode)
{
if (itemNode.Attributes["isComments"].Value == "no")
{
ndMessageId = itemNode.SelectSingleNode("MessageId");
sw.WriteLine(string.Format("MessageId={0}", ndMessageId.InnerText));
ndSeverity = itemNode.SelectSingleNode("Severity");
sw.WriteLine(string.Format("Severity={0}", ndSeverity.InnerText));
ndFacility = itemNode.SelectSingleNode("Facility");
if (ndFacility != null)
{
sw.WriteLine(string.Format("Facility={0}", ndFacility.InnerText));
}
ndText = itemNode.SelectSingleNode("Text");
//ndSymbolicName = itemNode.SelectSingleNode("SymbolicName");
//sw.WriteLine(string.Format("SymbolicName={0}", ndSymbolicName.InnerText));
sw.WriteLine(string.Format("SymbolicName={0}", ndText.Attributes["SymbolicName"].Value));
sw.WriteLine(string.Format("Language={0}", Enum.GetName(typeof(LanguageNames), language)));
sw.WriteLine(ndText.InnerText);
sw.WriteLine(".");
sw.WriteLine("");
}
else
{
ndText = itemNode.SelectSingleNode("Comment");
sw.WriteLine(ndText.InnerText);
}
}
sr.Close();
sw.Close();