提供多国使用者的软件,界面上的文字也需要能够切换成不同的语言,这被称作多语言化。WinCC的控件中中的文本可以分别输入中文和英文来实现多语言化,在这里输入的文本会被添加到WinCC项目数据库的TXTTable表中,在WinCC的文本库页面可以对翻译的内容进行编辑。但是在脚本中也有许多用于提示或记录的文本,WinCC没有为脚本中的文本提供翻译的功能。
在过去的一些项目中见过两种简陋的解决方法,一种是在脚本中分别写两条不同语言的文本,然后用if/else判断当前语言环境,从中选择一条文本输出,这样做的缺点是需要在写代码时去翻译其中的文本,而且夹杂了用于多语言的语句,使得代码的可读性特别差;另一种方法是把多语言化的代码提取出来封装成函数,在函数中集中翻译,这种方法相比前一种更加合理,但是同样是用if/else翻译文本,代码示例如下,可见并不利于查看和编辑,如果需要再添加第三种语言,此刻就会非常难操作。
借鉴上述的第二种方法,在代码用一个函数翻译文本,但函数中用其他更好的方法去实现文本的翻译,所用的方法要满足以下要求:
- 能够在类似于Excel表格的环境中编辑翻译的文本;
- 需要添加其他语言的翻译时,能够方便的添加;
- 能够随项目移植,即存储翻译文本的文件能够随项目程序拷贝;
- 项目中经常需要集成两个不同部分的项目程序,所以要能够方便的将两个项目程序的翻译整合在一起。
根据上述要求的限制,如下一些方法将不能采用:
- 不便于依靠WinCC文本库的TXTTable数据库表存储脚本中的翻译,实际使用中文本库中的内容非常混乱,不能确定哪些文本是脚本翻译中需要的,整合两个项目的程序时不便于操作,不能满足第4点要求。
- 不能另建一个数据库存储翻译文本,也不能用用户归档存储翻译文本,因为拷贝项目时不会拷贝数据库中的数据,不能满足第3点要求。
目前所想到的较好的方法是用CSV文件存储翻译文本,依靠ADO对象能像数据库一样用SQL查询CSV文件的内容;可以用Excel打开CSV文件进行编辑;需要添加其他语言时只需再CSV文件中新增一列,不需修改脚本;把CSV文件放在项目程序文件夹下,会随着项目程序一起拷贝。下面将介绍具体实现方式。
脚本内文本多语言化的函数示例
函数语法如下:
Function TranslateText(text, iLangID)
参数:
- text:输入的原文本;
- iLangID:输入文本的语言ID。
返回值:
- 如果当前语言环境与输入的语言ID相同,则返回原文本,如果不同,则查询原文本对应的翻译文本并返回该文本。
示例如下:
HMIruntime.Trace TranslateText("abc", 1033)
语言ID的全称叫区域标志符(locale identifier,缩写为LCID),WinCC支持的语言及对应的LCID如下:
- 1028 – Chinese (traditional)
- 1031 – German
- 1033 – English
- 1034 – Spanish
- 1036 – French
- 1040 – Italian
- 1041 – Japanese
- 1042 – Korean
- 2052 – Chinese (Simplified)
对于其他语言,虽然在WinCC中不支持,但是依然可以应用于脚本文本多语言化。其他地区的LCID可以从如下网站查询:
http://www.mytju.com/classCode/tools/LCID.asp
如何存储翻译文本
用CSV文件存储翻译文件,用Excel打开CSV文本示例如下:
- ID:是一条文本的顺序号,翻译的代码并不依靠ID,因此ID可以随意更改,只要不与其他ID重复;
- TextGroup:这是一个预留的字段,用于对翻译文本分组,因为工作中的WinCC程序经常要集成其他部门的程序,通过文本分组便于翻译;
- SourceLcid:说明代码以哪个语言的文本去查询翻译,这个字段提供给翻译者查看,告诉翻译者不要去修改原文本,只能修改其他需翻译的文本;
- L1033:英文文本;
- L2052:中文文本。
如果需要添加第三种语言,只需新增一列,列名用“L”+LCID命名。例如新增德文,新增一列命名为“L1031 ”,然后该列下面填写翻译。
CSV是一个以逗号分隔内容的文本,用记事本打开显示如下。
通过ADO查询CSV文件要求字符是ANSI编码,否则查询出的汉字是乱码,而用Excel编辑CSV文件时要求字符编码是UTF-8,否则看到的汉字都是“????”,保存后汉字的内容也就丢失了。这是目前尚未解决的缺陷,编辑时要记得对文件转码。用记事本打开CSV文件,点击“另存为”可以修改文件编码。
CSV文件的同一文件夹下还需要有个schema.ini文件,该文件说明了CSV文件的分隔符,如何判断列的类型等。如果没有schema.ini文件,ADO会根据windows注册表的配置值去处理CSV文件,有可能在某些电脑上不一致,导致读取失败,所以要建立schema.ini。schema.ini文件内容如下。
[Language.csv] Format=CSVDelimited DecimalSymbol=. ColNameHeader=True Col1=ID Long Col2=TextGroup Text Col3=SourceLcid Short Col4=L1033 Text Col5=L2052 Text
关于schema.ini文件的详细介绍可以查阅微软官方文档:https://docs.microsoft.com/zh-cn/sql/odbc/microsoft/schema-ini-file-text-file-driver?view=sql-server-ver15
如何用ADO查询CSV文件
ADO除了可以查询关系型数据库,也可以查询非关系型数据源,例如CVS文件。建立ADO连接需指定一个“Provider”,即驱动引擎,查询CSV文件用的“Provider”是“Microsoft.Jet.OLEDB.4.0”或“Microsoft.ACE.OLEDB.12.0”,Jet引擎可以访问office 97-2003,ACE引擎是新的,可以访问Office 2007,对于访问CSV文件这两个引擎没有太多区别。
WinCC附带安装的SQL Server中带有“Microsoft.Jet.OLEDB.4.0”,从Server Objects -> Linked Server -> Providers中可以查看到。
关于ADO的详细使用说明可以查阅微软官方文档:https://docs.microsoft.com/zh-cn/sql/ado/guide/appendixes/using-ado-with-microsoft-visual-basic
多语言函数的实现
存储多语言翻译文本的文件命名为Language.csv,Language.csv和schema.ini都存储在项目文件路径内的“\GraCS\Translation”文件夹下。
首先TranslateText()函数会通过传入的语言ID与当前环境语言ID对比,判断是否需要翻译,如果输入的文本与当前环境语言一致则直接输入,不需要经过翻译。如果需要翻译,则查询Language.csv文件中对应文本的翻译。如果翻译者还未填入翻译内容,即翻译文本为空,那么还是输出原文本。如果Language.csv文件中查询不到输入的文本,说明这条文本是代码中新加的,将通过代码在CSV文件中新加一条数据,翻译者补充翻译内容后再执行该函数就可以输出翻译内容。
Function TranslateText(text, iLangID) ' '根据语言ID判断是否需要翻译 ' If HMIRuntime.Language = iLangID Then ' TranslateText = text ' Exit Function ' End If If Trim(text) = "" Then TranslateText = "" Exit Function End If Dim conn, connStr, rs, SQL Dim dataDir Set conn = CreateObject("ADODB.Connection") Set rs = CreateObject("ADODB.Recordset") '把CSV文件作为数据源用SQL查询 dataDir = HMIRuntime.ActiveProject.Path & "\GraCS\Translation" connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & dataDir & ";Extended Properties='text';FMT=Delimited" conn.ConnectionString = connStr conn.Cursorlocation = 3 conn.Open '查找最大ID Dim NextId SQL = "SELECT Max(ID) as MaxId FROM [Language.csv] " rs.Open SQL, conn, 1, 3 If IsNULL(rs("MaxId")) Then NextId = 1 Else NextId = rs("MaxId") + 1 End If rs.Close '查询指定文本的翻译 SQL = "SELECT * FROM [Language.csv] where L"& iLangID &" = '"& text & "'" rs.Open SQL, conn, 1, 3 ' HMIRuntime.trace rs.Fields.Count & " columns found." &vbNewline ' Dim field ' For Each field In rs.Fields ' HMIRuntime.Trace field.Name&vbNewline ' Next If Not rs.EOF Then If IsNUll(rs("L"& HMIRuntime.Language)) Or Trim(rs("L"& HMIRuntime.Language)) = ""Then TranslateText = text '无翻译则输出原内容 Else TranslateText = rs("L"& HMIRuntime.Language) '取得翻译的文本 End If Else TranslateText = text '添加新的翻译 rs.AddNew rs("ID") = NextId rs("SourceLcid") = iLangID rs("L"& iLangID) = text rs.Update End If rs.Close conn.Close Set rs = Nothing Set conn = Nothing End Function
关于ADODB.Connection对象的使用查看:https://docs.microsoft.com/zh-cn/sql/ado/reference/ado-api/connection-object-ado
关于ADODB.Recordset对象的使用查看:https://docs.microsoft.com/zh-cn/sql/ado/reference/ado-api/recordset-object-ado