多国语言版本的编码要点

来源:互联网 发布:防御矩阵2 指挥官 编辑:程序博客网 时间:2024/04/28 18:19

◆本地化产品的整体步骤

1.在产品起始开发文档中要明确说明,产品本地化是开发周期中的一个重要环节,不应该把本地化放到开发完成时做,这样会带来本地化居多不便;

2.本地化测试应该在产品功能稳定时立即启动, 这时候无需开发一个本地化版本,而通过伪本地化方面或Pilot-language 本地化方法来先行测试;

3. 在用户界面稳定后,其他版本的本地化工作需要马上启动;

4.在原始资源中避免表达错误,语法错误;

5. 本地化资源外包:本地化工具包有一套工具,资源文件,二进制文件,其他本地化信息,这些都提交给本地化外包公司;本地化外包公司与开发人员的联系;翻译的术语要跟软件的背景适宜

 

◆关于资源本地化

1.  关于字符串:

AAvoid Run-Time Composite Strings 避免运行后动态组合字符串

When Variables Are Necessary, Use Unique Names变量一定要用时,用唯一名称

Win32 -- FormatMessage:一般用于多变量的警告或者消息语句中

.NET Framework -- String.Format能够处理多个变量的现实

Do Not Compound Several Variables不要将多种类型的变量混合

Keep Sentences in a Single String一个句子需放到一个string里面表示

Watch Your String Buffer Sizes  考虑字符串的buffer大小

用例:A

char szString[] = "Are you sure you want to delete the ";
char szFinalString[cbMaxSz]= szString + szDelObject + "?";
其中,szDelObject在程序运行时,可能为:file directory  subdirectory
=>换成下面三个完整的句子, 且针对不同的语言时翻译会更好理解:
"Are you sure you want to delete the file?";
"Are you sure you want to delete the directory?";
"Are you sure you want to delete the subdirectory?";
另外, 对于单一字符串,最好针对特定的上下文环境,分别列出,如
Menu_open = "open"
Dialog_open = "open"
Button_open = "open"
因为,可能有复数,性别的不同,或者用于不同语言时单一字符会根据上下文转译。这样, 对于可能存在这种境况的单一字符,最好做到每个上下文列举一个字串。

用例:B

用例A中的句子可以用下面的结构来代替
Del_File = "Are you sure you want to delete the %s ";
并附文档说明:%s 可能为file directory  subdirectory
另外,有多个变量时,尽量能表明变量的顺序:如
Memory_Error = "Not enough memory to %s the file %s.";
该句中有两个%s 存在的问题:当有些动词和名词位置摆放位置不同的语言时,就会出现错位:
如芬兰语翻译后的句子为:
"Liian vähän muistia tiedoston avaamiseen FileName1."
而,芬兰语正确的句子为:
"Liian vähän muistia tiedoston FileName1 avaamiseen."
解决方面是:将两个%s 用出现的次序分别标明, 
"Not enough memory to %1 the file %2."
这样芬兰语翻译后为:
"Liian vähän muistia tiedoston %2 %1." 容易替换对应的字符

用例:C

采用了message table

// Sample.mc

LanguageNames=(German=2:msg00002)

 

MessageId=1 SymbolicName=IDS_NOFILE

 

Language=English

Cannot open file %1.

Language=German

Die Datei %1 kann nicht geöffnet werden.

 

MessageId=2 SymbolicName=IDS_OTHERIMAGE

Language=English

%1 is a %2 image.

 

Language=German

%2-Abbild ein %1 ist.

 

主程序里面调用情况:

// lpBuf must be large enough to hold the formatted message!
DWORD langID = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN);
HMODULE hModule = LoadLibrary(...);
TCHAR lpBuf[60];
LPVOID lppArgs[10];
DWORD len = FormatMessage(
   FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY,
   hModule, idMsg, langID, lpBuf, sizeof(lpBuf)/sizeof(TCHAR),
   lppArgs);

用例:D

String.Format("Not enough memory to {0} the file {1}", sFunc, sFile);

 

用例:E

最极端的用例为

 "%d:%d%s on %s, %s %d, %d"

不知道何意:

提供翻译时,可以改为类似于:

"%d %1 has %2 internal %3." 即每个参数唯一标示

当然更好的话,把每个参数做一些说明。

 

用例:F

下面语句不妥:

"When this box is checked, Windows NT does not"  =词句没有结束于标点符号处

"automatically display the user name of the last person"

"to log on in the Authentication dialog box."

应该改为:

"When this box is checked, "  =(第一个句子)

"Windows NT does not automatically display the user name of the last person

to log on in the Authentication dialog box." => (第二个句子)

用例: G

"Press Ctrl+Alt+Del to restart."

翻译为德文的话:

"Drücken Sie Strg+Alt+Entf, um den Computer neu zu starten."

可见,buffer大小有了很大的改变。

在获取这个字符串的时候,最好用动态分配字符串大小,或者采用最大的缓冲区大小。

关于这一块,将在UI中介绍。

 

 

 

 

2. 关于UI

AElement Resizing尽量减少UI界面上控件更换尺寸大小

Localizability of UI Controls界面控件本地化

Avoid Text In Graphics避免在图片上包含文本串

 

2.1 Element Resizing

UI中的静态文本尽量留出来多些空间 这样多国语言版本翻译的时候,基本上不会出现再对各个空间的大小重新设置了。

                          1.1

 

上图1.1中很好的将“Name:”,“Initials”, Mailing Address”的空间位置调整到当前界面上合理的最大位置,基本上满足了其他版本就无需要调整了, 有多大的位置基本上需要一个经验,当然,可以将此翻译的最大字数做一个限定;

 

又如下例:

1.2中左边的静态文本框与右边的Edit框之间都留下了一定的空间,这样就能基本满足多国语言版本翻译的时候不用在重新调整尺寸。

                             (图1.2)转到德文版本时

                         1.3

另外, 在设计和本地化对话框时,应该将软件测试于不同的显示屏幕上或不同的分辨率上,应该在这些情况下都显示正确;特别是那种运行用户更改界面字体或拉升界面大小的界面。

如,在xp系统下,允许用户更改系统字体的尺寸,以及像标题工具条,菜单之类的系统可自画的控件字体;示例:

                        1.4

Resize对话框时保证各个控件位置协调:如果你需要使用系统对话框,如打开文件系统对话框,加入到你的应用程序中,或者做一个类似的对话框,要考虑到这类对话框都有调整整体大小的功能;这类系统对话框尽量使用系统自带的对话框来代替,这样不同操作系统下面的本地化不需要再行考虑。

 

保证对话框中的各个控件Tab顺序正常  如果对话框中的控件支持Tab调换功能,最好是现各个控件的Tab顺序正常,自左到右,自上而下;

                           1-5

能书写文本的控件设置多行属性:一般来说,各国语言的表达内容差异很大,包含字符数目差别有时还很大, 如果在空间上显示文本信息,一般需要设置控件属性MultiLine,如Edit控件,Check按钮,radio按钮等

示例:上图1-5radio按钮内容没有允许多行,就出现自动超出对话框的横向空间。

 

可变长度的字符串要多出一行位置显示因为是可变长度的,可能很长,如果留出位置能容纳特殊长度,

示例:

                                1-6

其中第一行“Welcome to the %s  Registration wizard, 如果一个外国人名称很长的,如

ABCDEFG 这类,放上去的话,用一行显示就不够,留传位置,可以尽量避免以后修改界面控件的大小。默认多多字符串的空间需要留出空余的30%大小,来为多国语言准备, 而短的字符串,可能留出空余的位置需更多。

 

2.2 Localizability of UI Controls

尽量避免使用句子不完整,要使用整句当使用界面上句子不完整时,如果翻译成不同版本时,一个句子的表达顺序不同,造成了界面需要调整。

示例:

                    2-1

2-1 是英文版的一个表达方式, 2-2是另外法语版的同样意思表达,可以看出来表达的顺序有改动, 这样在做下面的版本时, 需要调整edit框的位置,很麻烦。

                     2-2

                    2-3

解决方法就是把话说完整, 用图2-3设计方法可以解决上面的问题。

 

避免控件设计时位置重叠  像按钮,下列列表框等控件不要放在其他控件上面,这样当需要翻译时,被隐藏的其他控件容易被漏掉。

示例:

                           2-4

上图2-4中, Accept按钮的位置把Edit按钮覆盖了, Decline按钮的位置把Issuer Statement按钮位置覆盖了,在多国语言化时如果不重新排版按钮位置, 按钮大小不能延伸到所需的长度;就是可以重排按钮位置的话,也没有办法来重排,因为没有空间了。

                           2-5

上图2-5中,Edit Properties按钮应该是被Accept按钮完全遮住的, 但由于前者翻译的字符较多, 按钮位置需要拉伸来显示这个字符串,但为了要保证前者被后者覆盖的要求,仍然需要调整Accept按钮的位置。

 

避免按钮是一个变量文本按钮上的文本不应该是一个动态加载的变量,而应该是在编辑的时候通过按钮属性值添加固定文本,并在此时将按钮文本和按钮大小调整适中位置。

 

图片和图标中避免加入特定文化内容图片中尽量做到不要包含特定区域定义的内容背景, 或者文化,比如说,图标中包含国旗,包含具体的人种, 肤色等,这样本地化时,这些内容有时会遭到另外一些有差异背景的用户的抵触或反感。

示例:

下图2-6中,左边的图是美国本地表示邮箱的标记,但这个图标如果给一个欧洲人使用时,

                                  2-6

他们很难将这个面包盒加一个柱子的图标跟邮箱联系起来,虽然美国的有些产品和文化基本国际化程度很高。最好还是选择右边的那个带有信封的并有信纸的图标表示容易让人理解。

          2-7

上图2-7中,图表表示一个向导的概念,上述也是美国的一种老的文化积淀下来的一个体现,但对其他的地域文化来说,他也是一个外来物, 理解有问题, 也会被其他敌视国家所排斥的。

 

                      2-8

2-8中表示停止的一个手势,但左图用了身体的具体部位,并且带有具体肤色。首先,张开手在其他国家并一定具有表示停止的意思;另外,身体部位大小和肤色会明显激起不同人的各异情绪,有抵触感,有厌恶感等。

 

有如下图2-9 左边将具体人的性别表明了,并且个人的职位高低也初略表明了。由于在不同国家对不同性别地位不同,比如伊斯兰国家,女性的地位比较低,这样的图在他们国家当前被使用几乎就不会被接受。用右边的阴影图表示的话,就不曾在这样的一个问题,因为模糊了性别。

 

                                 2-9

另外,避免图片中带有鲜明的宗教内容,避免带有特定的政治内容,也是一定要注意到的。

 

2-3 Avoid Text In Graphics

避免图片上带有文本信息:除了对各个版本来说都是一样的文本,如公司的logo文本。

为什么这样说呢,因为如果你要本地化产品,每个图片上的文字都需要你先翻译过来,然后再提交给制作图片的人员,将对应文字附上背景图片,作为一个整体图片。这个过程对一个版本来说不是太花时间,但是一次出来多个语言的本地化的时候,就可以看到他带来的幅面效应,即花时间,又重复劳动。

                             2-10

 

3. Isolate Localizable Resources(分离本地化资源)

本地化软件,其中的源文件中不应该带有这些本地化资源,翻译时难以找到,因为一般来说,编程人员和翻译人员是不同的人来担当, 这些硬编码都只有在软件测试时才能发现。

示例:

3-1Edit框中对应的资源是硬编码,Unknown Modem只能在测试的时候才会发现,给这个多国化过程带了潜在的影响。

 

需要本地化的有:

菜单  消息 对话框 提示 图片 声音 工具条 状态条 常量

当前最简单也是直接的方法就是把上面这些需要本地化的资源导入一个类似资源库里面,如Windows资源文件,。Net  二进制文件, 处理网络资源的数据库等。这类资源库的特点有,容易编辑, 增删时无需编译源代码,它包含:

a.  UI 资源: 可以保证功能性的前提可以任意本地化.

 

                            3-1

b.  用于产品自适应的资源 (字体,locale信息,目录名,账号名称,等). 这些资源需要根据特定规定进行本地化, 不正确的本地化方式会造成功能影响。这里资源需要与应用程序分离,并使用时需要访问当前的操作平台

c. 调试资源调试资源不需要本地化.

d. 功能性资源 (注册表键值, 功能调用, 组建通讯的字符串等). 这些资源在不影响功能性的前提下用本地化

 

为了减少复杂性,并提高编码的灵活性,将b类资源数目越小越好。比如说,一个需要本地化的b类资源同样的资源,如“日期”,使用一个实例,避免多个实例使用多个资源,都采用同一个“日期”资源。其中可以简单的将上面的资源分为两类,ab需要本地化, cd无需本地化。为了不需要d类资源被本地化,可以将这些资源放置在应用程序的本地资源中,不需要导出,这样做,可以避免:

a.      避免不需本地化的资源翻译的工作;

b.     功能性字符串被翻译,然后影响了功能操作,如用一个“open”命令,翻译成法文“Ouvrir”这条命令就不知所云了;

C.期待服务器或操作系统都是英文的,如下面

if ( (_tcscmp(lpBuffer,TEXT("SYSTEM")) == 0) ||

     (_tcscmp(lpBuffer,TEXT("LOCAL SERVICE")) == 0) ||

     (_tcscmp(lpBuffer,TEXT("NETWORK SERVICE")) == 0)

上述代码是判断用户是否是系统管理员,上述应该用api函数来获取本地化的系统值
TCHAR szPath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath);

合理的方法有:

1.             将不需要本地化的资源放到一个头文件(用c语言编程时.h文件);

2.             不同语言版本的资源,不要改变对应资源的id

3.             将不再需要的资源从资源库中剔出掉

 

关于输入,输出,显示

字体

软件中往往需要选用字体来正确的显示字符或者字形, Windows 2000系统中引入了OpenType fonts, font fallback, and font linking–来解决这类字体选择的问题

OpenType fonts:基于Unicode 支持丰富的字符集与字形的映射, Windows核心字体 (Times New Roman, Courier New, Arial, MS Sans Serif, and Tahoma) 包含了中西欧, 希伯来语(Hebrew, 阿拉伯语(Arabic, 希腊语(Greek, 土耳其语(Turkish, 波罗的语(Baltic, 古代斯拉夫语(Cyrillic))的字母, 和越南(Vietnamese)形体,但没有包含中东形体字符集,使用以上的字形都会映射到正确的字体;

font fallback:基于Unicode Uniscribe检测到当前选择的字体无法显示当前的形体字时,会自动转到系统系统默认的字体来显示形体字。比如说,在windowXP系统下,用户选择Tahoma字体,开始输入英文文本,然后输入希伯来语文本,然后输入泰卢固语文本,由于Tahoma字体是OpenType字体,他支持拉丁文字体和希伯来语文本,但不支持泰卢固语文本。Uniscribe会检测到缺少泰卢固语字体的支持,会自动选择使用font fallback ,即Gautami字体来显示形体字。虽然font fallbackxp系统下包含了像泰卢固语的印第安形体字,但Windows 2000系统不存在这种机制。对于大部分形体字,他们的font fallback都是Microsoft Sans Serif(属于一种OpenType fonts),对于印第安形体字的font fallback映射到另外一种字体了。

font linking:将不同的字体(font linking)连向某个字体(basic字体),一旦你使用font linking,你就可以用basic字体显示基本字体不存在的码点,如将hangul font Japanese font Tahoma fontbasic字体)建立连接关系,这样就可以用Tahoma font 来显示韩国和日本字体了。

注意:用font fallbackfont linking,自动选择后的新字体的大小会和原始字体大小一样,比如说,选择8-point Tahoma字体,先开始输入英文,然后输入日文时会自动选择8-pointMS UIGothic字体,这样的日文字体很难看清楚了;另外,这两种字体也不会第一时间内选择最适合的字体来显示对应的字符。

 

1 window32 字体选择

为了使你应用程序利用上面描述的系统字体支持,应该遵循下面几项:

A 不要用硬编码来表示字体名称,因为字体名称对不同机器或系统可能意味着不同的默认字符集,如 Arial字体名称在Arabic语的机器上默认为“Arial 178

B 不要假设某种字体被安装了

C 不能假设所选字体支持目标字形。如,不可能用Miriam(一种Hebrew字体)来表示hiragana字形。

D 不要用硬编码来定义你使用的字体大小,而应该根据所要显示的字形而变化,因为大部分英文字符需要5*7 grid来表示,而日本的字形需要用16*16grid表示才能看清楚,中国字体至少要24*24grid来表示,泰国字形至少要8个像素的宽度,22个像素的高度来表达。

如下图:

           4-1

2  资源中对话框的字体选择

不同语言版本,或者同一个语言版本的系统字体会不尽相同。下面的例子中,对话框资源中采用了MS Sans Serif字体, 它是一个位图字体,仅包含西欧国家的形体。如果应用程序本地化位土耳其或者日本语言版本,在不修改字体名称,界面上的文本就会显示一个“口”某样。

DLG_NLS DIALOG DISCARDABLE 0, 0, 344, 260
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "NLS APIs"
FONT 8, "MS Sans Serif"

                     4-2

理想的字体应该选择应该跟桌面界面(Shell)字体一致, 因为默认shell字体会因系统不同而选择不同的字体(英文操作系统下,为MS sans Serif 阿拉伯语言系统下,为Tohoma),最好是使用高级描述的字体名称,即“MS Shell Dlg”, 它会根据系统下的字体替换原则影射到合适的字体。我个人经验感受,用它的话,在多国语言系统下应用程序的资源对话框尺寸不用再调整,就可以和内部的控件融合得很好J, 即:

DLG_NLS DIALOG DISCARDABLE 0, 0, 344, 260
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "NLS APIs"
FONT 8, " MS Shell Dlg "

3. 运行时字体选择

在代码中使用硬编码定义字体名,和在资源文件中用硬编码定义它都会破坏UI。字体选择应该要灵活并根据上下文,不应该直接调用 CreateFont CreateFontIndirect API函数,这样字体名称会被硬编码到LOGFONT结构中,而应该用 EnumFontFamiliesEx,它通过字符集而不是通过字体名称来枚举出当前系统下支持字体特征的所有字体。

LOGFONTDEFAULT_CHARSET不是真正的字符集,在window2000xp下面要做两件事:

A 尝试选择用户命名的字体包含的当前系统字符集;

B  如果对应的字体不支持系统字符集,它会选择一种字符集,并支持字符集的字体。

DEFAULT_CHARSET应该用于Unicode编码的字符串显示。

 

对于大部分东亚的语言它的字体名称都有两个,英文名称,和本地化名称,这样用CreateFont CreateFontIndirect就可能有问题了。EnumFonts, EnumFontFamilies, and EnumFont–FamiliesEx会自动选择语言的。

 

另外,运行时语言选择时,可以弹出公共对话框,让用户选择字体格式。

 

分行/字单位划分

拉丁文字单位的划分可以用空格,tab字符,或者连字符等来判断,另外一些乡泰国文字等,字与字之间没有空间,需要从语法分析上才能判断一个字,其他的语言也有各自的字单位的表示方式。

Line/Word Breaking in Win32

如果需要显示的文字都是纯文本形式的,同样类型,字体粗细,颜色,等都一样,就可以用 一般的TextOut ExTextOut, TabbedTextOut, DrawText来显示文本,用GetTextExtent来获取文本的长度。

 

支持复杂的输入模式采用Rich Edit Control控件,它支持多语言输入,提供断句断字的功能。

另外,UniScribe通过ScripBreak也能实现断字断句的功能。

 

输入,输出详细内容等有空再做整理,当前TV2TEL相关功能也用不上。

 

 

附言1(自己的建议):

(1)      多国语言的应用软件最好用Unicode编码;

(2)      尽量不要使用整张背景图最为对话框的背景,主要是在其他语言系统下,可能对话框大小有变化,要用同一张背景图的话,就有可能需要调整对话框的大小,以及对话框下面的各个控件[主要原因是:对话框的大小和背景图的大小在不同系统下面不是等比例伸缩的]

(3)      尽量在源代码里面定义对话框的大小,以及各个控件的相对位置。因为,如果下次要调整对话框大小了,还需要进入源代码去修改。这个对话框大小及相关控件的位置可以在资源编辑器里面调整[资源dll],这样就可以把源代码和资源dll的人员分开;并且这种设置对话框大小的硬代码,也有可能在不同操作系统下带来显示效果不一致[各操作系统的单位尺度不一致]

(4)      对话框的字体选择为“MS Shell Dlg”, Font大小可以根据显示需要调整

DLG_NLS DIALOG DISCARDABLE 0, 0, 344, 260
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "NLS APIs"
FONT 8, " MS Shell Dlg "

(5)      按钮里面包含文本时,这些文本应该直接在资源编辑器中编辑各种语言的版本,而不应该将此文本作为资源中的一个String资源,否则可能出现对应的字串在当前大小的按钮空间里面显示不完整;

(6)      按钮字画控件可以采用CButtonST3.9版本来完成,基本可以到达当前的所有需求;

(7)      静态控件,一般来说,要求有一个透明的背景,如下面

HBRUSH CxxxDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

       switch(nCtlColor)

       {

       case CTLCOLOR_STATIC:

              {

                               pDC->SetBkMode(TRANSPARENT);//透明

                            return (HBRUSH)::GetStockObject(NULL_BRUSH);

       }

   。。。

}