编写国际化代码的一些问题
Microsoft 公司 1997年4月7日修订目录
- 引言
- 在编码中使用本地语言
- 使用字符串表
- 在Microsoft Excel中使用字符串表
- 在Microsoft Word中使用字符串表
- 在Microsoft Access中使用字符串表
- 在运行中本地化文本
- 在代码中使用本地格式
- 格式化日期
- 格式化货币
- 格式化数值及分隔符
- 使用字符集
- 字符串操作
- 显示及打印文本
在Microsoft Office的以前版本中,如果你的应用中包含了正确的对象库,就可以用非英语的关键字来引用对象。但是在Office 97中,对象库不再本地化,你必须用英语关键字来引用对象。
注意:如果用户在Microsoft Excel 97, Microsoft Access 97, 或PowerPoint 97中打开以前本地化的VBA版本的应用时,代码中的非英语关键字将自动转化成英语。然而,用WordBasic写成的代码不能转化成英语的VBA代码。如果你的应用中使用了本地化的Word 6.0 或 Word 96中本地化的WordBasic代码,你用Word 97中的Word 类型库重新编译后,可在Word 97中运行。
在本文中,“本地化”指的是在控制面板的地区设置对话框中你所选择的地区。“对象库”指有.olb扩展名的文件,它决定了Visual Basic可理解的命令和符号即:你在Visual Basic模块中可使用的对象、性质、方法的名字。
这篇文章讲的是在Office 97 Visual Basic编程环境中有关书写国际代码的基本问题。有关本地化的更高级的话题,包括API函数,代码页的支持及键盘的规划请参考Nadine Kano 的Developing International Software for Windows 95 and Windows NT(ISBN 1-55615-840-8)一书。此书由Microsoft出版社出版,可在任何卖计算机图书的地方买到,或者从网上下载(http://mspress.microsoft.com/)。
当你编写国际代码时,你首先要考虑到你的消息如何提供给用户。在本地化的Microsoft Excel, Microsoft Word, Microsoft PowerPoint, 及 Microsoft Access中,错误消息用本地语言显示给用户。当你编写自己的应用时,你要自己翻译你的消息。
你可用以下几种方法将你的消息翻译成用户的本地语言。其一是在开发过程中建立一个字符串列表,这个表包含所有翻译成本地语言的消息,当你想显示一条消息时,直接从这个表中引用。因为字符串表独立于代码,所以比较好维护,但是,访问字符串表,尤其是表很大时,应用会运行较慢。另一种方法是在变量中指定消息内容,这样虽运行时较快,但因消息内容与代码混在一起而难于维护。
注意:因为Visual Basic 代码存在PowerPoint 的工程文件(.ppa)中,所以PowerPoint中不能使用字符串表。
为了使你的字符串表不被别人更改,你要把表隐藏。Microsoft Excel中,你可以把表放在一个worksheet中然后把这一worksheet隐藏或者以Microsoft Excel的附加项分发你的解决方案。在Word中,你可以把表放在文件中,把它另存为模版。然后作为全球模版分发你的应用。
当你建立你的字符串表时,你可使用Microsoft Excel引用指定区域的方法。如:下面的字符串表包含了翻译成英语、法语、德语的消息。
例子1 字符串表在Microsoft Excel应用中显示本地化文本。
使用字符串表前,先要定义Localized Strings列中的单元名。然后用Offset方法从相应的语言列中得到翻译后的文本。用英语显示一条消息时,Offset的参数是1,法语是2,德语是3。你可用以下方法获得列的偏移量:
先显示一个对话框询问用户的语言或国家选择,然后定义一个公用变量,用用户输入的偏移量给它赋值。
用Application对象的International性质指定Microsoft Excel的语言版本(xlCountryCode)或者操作系统的国家设置(xlCountrySetting),将结果转化为列偏移量,赋给一个Public型的变量。下面的代码根据你使用的Microsoft Excel的版本定义了偏移量值。
Public GlobalOffsetCode
Sub GetGlobalOffsetCode()
Select Case Application.International(xlCountryCode)
Case 1: 'US English
GlobalOffsetCode = 1
Case 33: 'French
GlobalOffsetCode = 2
Case 49: 'German
GlobalOffsetCode = 3
Case Else: 'US English as the default language
GlobalOffsetCode = 1
End Select
End Sub
以下代码用偏移量值显示一用户本地语言的欢迎信息。
WelcomeMsg = ThisWorkbook.Worksheets("LocalizationTable").Range _
("Welcome").Offset(0, GlobalOffsetCode).Value
MsgBox WelcomeMsg
你可用类似的技术改变对话框项目的文本,位置及大小,使你的代码真正是可翻译的。
你可在Word应用中建立类似的字符串表来显示本地化的文本。以下的字符串表包含译成英、法、德语的文本。
例子2 在Word应用中用字符串表显示本地化文本
因为Word不支持指定区域,你应该定义代表本地语言消息的常量,用这些常量作为表的行索引。
以下的常量适用于上述的字符串表。
Public Const iWelcome As Integer =1
Public Const iCustomerName As Integer = 2
Public Const iAcctNumber As Integer = 3
Public Const iNotValidMessage As Integer = 4
然后定义一个列变量,用以下几种方法给它赋值:
显示一个对话框询问用户语言或国家名,然后根据用户输入设置变量。
用Application对象的International属性定义Word 的地区版本(wdProductLanguageID)或用System对象的Country属性定义操作系统的当前国家设置。将结果转化成列值,赋予一个Public变量。
以下代码根据你的Word的语言版本指定字符串表的相应列。
Public iTheLang
Sub GetGlobaltheLang()
Select Case Application.International(wdProductLanguageID)
Case wdEnglishUS
iTheLang = 1
Case wdFrench
iTheLang = 2
Case wdGerman
iTheLang = 3
Case Else: 'US English as the default language
iTheLang = 1
End Select
End Sub
以下代码用行列变量显示一个用户方言的欢迎信息。
welcomeMsg = Documents("Welcome.doc").Tables(1) _
.Cell(Row:=iWelcome, Column:=iLangCol)
MsgBox welcomeMsg
有关在 Microsoft Access中使用字符串表的信息请参照“获得语言版本及国际化文本” 主页(http://www.microsoft.com/AccessDev/Articles/HowToBk.HTM)。你在Ken Getz 和Paul Litwin的Microsoft Access 95 How-To一书(Waite Group Press, ISBN 1-57-169-052-2)中可找到相关及更多的信息。此书在各计算机图书发售处有售。
除了使用字符串表,你还可以在运行时本地化文本。使用Select Case...End Select结构指定你的消息的恰当的翻译。例如:以下代码使用Word的International属性确定用户的地域给相应的变量赋值。
Public sWelcome As String
Public sCustName As String
Sub assignText()
Select Case Application.International(wdProductLanguageID)
Case wdEnglishUS
sWelcome = "Welcome"
sCustName = "What is your name?"
Case wdFrench
sWelcome = "Bienvennue"
sCustName = "Quel est votre nom?"
Case wdGerman
sWelcome = "Willkommen"
sCustName = "Wie hei?en Sie?"
End Select
End Sub
通过引用恰当的变量名来显示翻译后的文本。以下代码在对话框中显示一个用户本地语的欢迎信息。
Msgbox sWelcome
使用本地格式与显示本地语言一样重要。如果你的应用中使用了数字,日期,时间及货币,你要将它们转化成相应语言的格式。Visual Basic提供了几个函数通过地区设置转化数据为相应的格式。
在可能的情况下,请尽量用地区敏感的函数编写你的代码。这在你把字符串转化成数字和日期时由为重要。如:函数Str 和 Val永远假设’.’是小数点,而CStr, CDbl, CSng, CInt, 及 CLng则用当前操作系统的地区设置决定小数点是哪个分隔符。
不要在你的代码中输入日期字符串,因为每个国家的日期格式并不相同。即使地区敏感的转换函数函数也不一定能按你的意愿转换。如:以下代码在不同的地区产生不同的结果。
StartDate = "2/3/97"
NewDate = CDate(StartDate)
Msgbox Format(NewDate, "Long Date")
当这些代码运行于美国英语区,变量NewDate的值为1997年2月3日,而在澳大利亚英语区,它的值为1997年3月2日。这就造成了你程序的潜在错误源。但是,这在处理对话框输入时却非常有用。Cdate把用户的文本转换成其期望的日期。
作为一个程序员,你应该把日期写成文字,如#2/3/97#。这样Visual Basic能够正确的辨认出你想要得日期。在下面的代码中NewDate的值是1997 年2月3日还是1997年3月2日取决于程序员的地域,而不是用户的地域。
StartDate = #2/3/97#
NewDate = CDate(StartDate)
同样的,不要把货币值存成含有货币符号的字符串,因为货币符号因地域而不同。下面的代码除了在美元($)为货币符号的地区为正确外,在其他地区都会产生错误。
Money = "$1.22"
NewMoney = CCur(Money)
为避免这些错误,将货币值存成小数,如下例(这个例子假设在编程的地区’.’是小数点,但是代码在以任何符号为小数点的用户区域都能正确运行):
Money = 1.22
NewMoney = CCur(Money)
在美国,句号(.)是小数点。然而在大多数欧洲国家,逗号(,)作为小数点。在美国,逗号作为每千倍的分隔符,从小数点往左,每三位分为一组,而在欧洲,人们用句号或空格。
在Visual Basic中,函数Str 和 Val永远假设句号是小数点。在很多地区这一假设是不成立的。我们用CStr, CDbl, CSng, CInt, 及 CLng函数将其它的数据类型转换成你所需要的数据类型。这些函数用系统区域决定什么做为小数点。使用这些函数的更多信息请参阅Visual Basic帮助。
各种语言的字符被编成字符表,称为代码页。代码页允许操作系统为不同国家的字符集和键盘规划提供支持。任何语言的脚本都由其代码页刻画。Windows的每个外语版都用不同的结构支持某一字符集。例如:
单字节(SBCS):支持256个字符,每个字符由唯一的单字节字符值标识。欧洲语言的代码都是单字节(包括拉丁及非拉丁语)。双向字符集是单字节代码页,允许双向文本如阿拉伯语及希伯来语。
双字节(DBCS):支持成千上万的字符,每个字符由唯一的双字节字符值标识。远东语言如日语及中文使用这种代码页。
使用DBCS的地区,字符集包括单字节及双字节字符。这些地区的单字节字符遵从当地的8位国家标准,符合ASCII字符集。然而一些SBCS地区的字符被设计成DBCS的首字节。连续的首字节和尾字节组成一个双字节的字符。当你用DBCS开发应用时,你要考虑你的应用如何处理文件中的字符串,如何显示及打印字符。
统一编码标准(Unicode):所有常用字符都包含于这个双字节字符集中。Unicode是独立于语言的编码标准,从而统一了地区性。
Office 97中的每一个应用都支持Unicode标准,所以编程中的多代码页问题得到了解决。Unicode使你的应用存储、传输及处理数据更简单,但它并不格式化字符,你要本地化你的文本后显示给你的用户。
如果用户从Office 97 CD上的/Valupack/fareast目录下装入适当的NLS和字库文件,就可以交换美国英语和远东语言的Office 97文件。这些文件用于显示远东字符,读文件性质,读Office 95文件。关于交换美国英语和远东语言文件的更多信息请参考Value Pack帮助文件。
注意DBCS与Unicode不是同一个字符集。在必要的时候,ANSI字符与DBCS字符都可转换成Unicode,Unicode也可转换成ANSI字符与DBCS字符。
在使用DBCS的地方,一个文件可能既有单字节字符又有双字节字符。因为DBCS字符有两个字节表示,你的Visual Basic代码要避免切分字节。下面的例子假设TESTFILE是一个包含DBCS字符的文本文件。
Open "TESTFILE" For Input As #1 ' Open file for input.
' Read all characters in the file.
Do While Not EOF(1)
MyChar = Input(1, #1) ' Read a character.
' Perform an operation using Mychar.
Loop
Close #1 ' Close file.
当你从二进制文件中读入一定长度的字节时,请使用Byte数组而不是字符串变量来避免Unicode/ANSI字符转换。
Dim MyByteString(0 to 4) As Byte
Get #1,, MyByteString
当你用字符串变量通过Input 或 InputB从一个二进制文件读入字节时,因为Unicode的转换而导致结果不正确。
文件名及目录也包含了DBCS字符集
一个允许DBCS的应用要在Windows的DBCS版上显示DBCS字符。当你使用为SBCS设计的字体时,DBCS字符就不能在DBCS版的Windows上正确显示。如果你没有允许DBCS的字体或不知道哪一种字体适合你的环境,请使用System 及 FixedSys字体。注意System 及 FixedSys字体有一些大小的不同。当你的应用中要打印DBCS字符时,你也要做相似的考虑。
本文的内容代表了文章发表时的Microsoft的观点,它不是Microsoft的承诺,Microsoft不为发表后数据的精确性负责。