多语言开发规范

1 总体规范
1. 【强制】为了可以利用翻译平台支持程序提示语的翻译,切忌在一个工程中包含多个苍穹应用的提示语,不同苍穹应用的提示语应该放在不同的工程中。
2. 【强制】为了正常使用多语言产品,在提交中文元数据文件时,禁止提交非中文的元数据文件。

3. 【推荐】图片的多语言:原则上图片和文字需要做分离,这样在实现多语言时只要把文字抽取出来翻译。如果文字嵌入图片中则需要整个图片重新设计多语言。
2 多语言字段
2.1 单据设计文本类型处理
1.【强制】多语言环境下,单据设计时注意事项:文本类型的字段,有需要显示不同国家语言文字的,则应选择多语言文本控件。
2.【推荐】多语言字段勾选“通用语言“属性,可解决的问题:即使在其他语言下没有维护该语言的译文,以该语言登录云苍穹后,此字段显示为中文而不是空:
2.2 多语言字段设计规范
【推荐】多语言表的字段长度设置:字段长度根据业务实际情况设置,一般设置为500。
【强制】如果启用了通用语言的选项,对应的物理表中会增加一个字段,此字段的类型与多语言表中的字段保持一致
【强制】多语言表主键的字段类型为VARCHAR
2.3通用多语言自定义SQL
【推荐】代码使用orm查询会自动处理通用语言字段,对于直接用sql查询多语言字段值,需要判断该字段是否开启了通用语言,然后若当前语言环境对应的值为NULL则取通用字段上的值。

3 预插数据
3.1 预插数据规范
【强制】预插数据中不能填写分号,如果填写了分号,在制作多语言包时,分号会被识别为两个语句而截断,导致生成的语句在执行时报错。
【强制】在使用标准产品补丁进行多语言表的数据操作时,仅限于对简体中文数据进行新增、更新或删除操作,非简体中文数据由多语言产品补丁进行处理。
4 程序提示语
4.1中文词条与KEY写法规范
1. 【强制】程序提示语中的中文词条写法注意。
(1)中文词条要纯正,不要汉语然后夹杂着英文符号。
(2)词条的开头和结尾除非特殊原因最好不要留空格。
2. 【强制】中文词条中不要包含\n、\r这样的转义字符,也不要包含html标签。
比如,下面的中文词条:"保存成功。\n请检查这条记录。"其中包含了\n转义字符,在中文场景下加载正常,前端显示的时候会换行,然而,在其他语种下,会直接在界面上显示\n而不是换行,这是因为多语言处理的时候经过了很多步骤,包括抽取、加载、工具转换、记录进入数据库、加载记录等过程,最后加载出来的转义字符会有多余的\。如果确实需要这样的换行效果,可以使用占位符。也就是把转义字符与其他中文拆开后再连接起来。另外,html包含了<>这样的特殊字符,在后续处理的过程中会报错,所以也需要把html标签与其它中文拆开后再连接起来,改造方法与转义字符的相同。
3.【推荐】代码中只包含需要翻译的中文内容。不要包含任何的格式、转移字符、特殊符号等。有可能导致译文显示错乱。
4.【强制】资源文件中的KEY唯一(不区分大小写)
* 有些数据库对大小写不敏感,会导致潜在问题。
反例:


4.2词条拼接处理规范
1. 【强制】提示语必须是完整的句子,句子中的变量需要使用占位符替换。
通常遇到的使用场景如下:
场景1:当代码中的提示语中只包含一个需要替换的变量时,可以使用%s进行替换。
正例:
中文示例:第5条行程。
代码示例:ResManager.loadKDString("第%s条行程。", "CslScheme_6", "fi-bcm-formplugin", count)
说明:中文内容中的“5”是代码根据实际情况动态变化的,并且在这条语句中只存在一个变量需要动态替换。因此可以使用%s进行替换。
场景2:当在提示语中需要按照顺序位置替换多个参数内容时,可以使用%1$s,%2$s按顺序使用。
正例:
中文示例:第2行“价格”不能为空。
代码示例:
ResManager.loadKDString("第%1$s行“%2$s”不能为空。", "SrcPurListMustInput_1", "scm-src-common",i+1,displayName))说明:要使用%1$s,%2$s,%3$s等这种带参数位置的占位符,而不要使用%s,因为中文的语序跟其他语种的语序可能不同,这会导致翻译不准确或者翻译错误。在这个中文示例中,“2”和“价格”会随着录入人员实际录入的情况不同而发生变化。因此需要使用2个参数来进行变量替换。这时就需要使用%1$s和%2$s来进行替换。在代码示例中i+1用来替换行数,displayName用来替换具体字段内容。
场景3:当进行页面提示时,如果使用到了表单中某一字段控件的名称时,建议通过元数据来获取该名称,并通过占位符的方式进行页面提示。这样可以保证提示语内容与字段描述一致,同时字段描述修改时,不会影响代码中提示语内容,代码无需修改。
正例:
MainEntityType dataEntityType = EntityMetadataCache.getDataEntityType("页面编码");
Map<String, IDataEntityProperty> fields = dataEntityType.getAllEntities().get("页面编码").getFields();
String username = fields.get("字段标识").getDisplayName().toString()getView().showTipNotification(ResManager.loadKDString("%s已绑定环境,不允许新增环境。","Test_0","工程标识",username);说明:%s代替字段控件的名称
2. 【推荐】使用带参数位置的格式化形式,ResManager.loadKDString就可以满足格式化转换其他语言的需要。
正例:
代码示例:
ResManager.loadKDString("第%1$s行%2$s不能为空。", "SrcPurListMustInput_1", "scm-src-common", i, displayName);反例:
代码示例:
ResManager.loadKDString(String.format("第%1$s行%2$s不能为空。", i, displayName), "SrcPurListMustInput_1", "scm-src-common");可以使用String.format,但必须位于ResManager.loadKDString外层。
3. 更多拼接问题示例
(1)不成对双引号或单引号(含全角和半角)
反例:
ResManager.loadKDString("and函数的最终结果必须是“通过“或”不通过”。", "AndCompareCalculate_1", SYSTEM_TYPE)));
正例:
ResManager.loadKDString("and函数的最终结果必须是“通过”或“不通过”。", "AndCompareCalculate_1", SYSTEM_TYPE)));
(2)句首为冒号、顿号、逗号、全角句号、右方括号、右圆括号(含全角和半角)
反例:
errorMsg.append(number).append(ResManager.loadKDString(":存在下级资料,不允许个性化。", "BaseDataIndividualizer_6", SYSTEM_TYPE));
正例:
errorMsg.append(ResManager.loadKDString("%s:存在下级资料,不允许个性化。", "BaseDataIndividualize_6", SYSTEM_TYPE,number));
(3)句末为左圆括号、左方括号(含全角和半角)
反例:
String logStr = ResManager.loadKDString("初始化共享中心:", "WorkDateUtil_0", "ssc-task-formplugin") + centerId + ResManager.loadKDString("的工作日历(", "WorkDateUtil_1", "ssc-task-formplugin") + startDateCopy + ", " + endDateCopy + ResManager.loadKDString("),上午工作数量:", "WorkDateUtil_2", "ssc-task-formplugin")
+ morning_workDateList.size() + ResManager.loadKDString(",下午工作数量:", "WorkDateUtil_3", "ssc-task-formplugin") + afternoon_workDateList.size() + ResManager.loadKDString(",工作日历分录dateentry:", "WorkDateUtil_4", "ssc-task-formplugin") + days;
正例:
String logStr = ResManager.loadKDString("初始化共享中心:%1$s的工作日历(%2$s,%3$s),上午工作数量:%4$s,下午工作数量:%5$s,工作日历分录dateentry:%6$s", "BaseContent_1",SYSTEM_TYPE,centerId ,startDateCopy ,endDateCopy,morning_workDateList.size() , afternoon_workDateList.size(),days);
(4)句子末尾为"从"、"但是"、"或者是、"第"
反例:
errorMsg.append(ResManager.loadKDString("优先级和时效分录第", "TaskRuleChildSave_4", "ssc-task-opplugin")).append(listSeq)
.append(ResManager.loadKDString("行:优先级越高,设置的时效应该越小", "TaskRuleChildSave_5", SYSTEM_TYPE));
正例:
errorMsg.append(ResManager.loadKDString("优先级和时效分录第%s行:优先级越高,设置的时效应该越小。", "TaskRuleChildSave_4", SYSTEM_TYPE,listSeq));4.3静态常量处理规范
1.【强制】程序提示语静态常量写法。
kd.bos.permission.formplugin.AdministratorEditPlugin
以上JAVA类的中文静态常量:
private static final String MSG_CANCEL_EDITNEWADMIN = "新增管理员未保存,是否放弃保存?"; private static final String MSG_CURADMIN_SAVEORNOT = "当前管理员未保存,是否放弃保存?";
用转换工具处理后变成:
private static final String MSG_CANCEL_EDITNEWADMIN = ResManager.loadKDString("新增管理员未保存,是否放弃保存?", "AdministratorEditPlugin_0", "bos-permission-formplugin");
private static final String MSG_CURADMIN_SAVEORNOT = ResManager.loadKDString("当前管理员未保存,是否放弃保存?", "AdministratorEditPlugin_1", "bos-permission-formplugin");这样的处理,在运行时不会根据不同的登录语言返回相应的译文。
this.getView().showConfirm(MSG_CANCEL_EDITNEWADMIN, MessageBoxOptions.OKCancel,new ConfirmCallBackListener(eventInfo, this));
解决方案:增加一个获取提示语的方法:
private String getMsgCancleEditNewAdmin(){
return "新增管理员未保存,是否放弃保存?";
}
原来使用静态常量的地方修改为调用获取提示语的方法
this.getView().showConfirm(getMsgCancleEditNewAdmin(), MessageBoxOptions.OKCancel, new ConfirmCallBackListener(eventInfo, this));
程序提示语转换工具加工后的代码为
private String getMsgCancleEditNewAdmin(){ return ResManager.loadKDString("新增管理员未保存,是否放弃保存?", "AdministratorEditPlugin_0", "bos-permission-formplugin");
}2. 【推荐】不能使用static来修饰中文静态常量,要按照推荐的方式对代码进行修改。开发完成后,可以使用多语言检查工具来进行硬编码代码检查。保证代码不存在中文硬编码问题。
4.4枚举类型处理规范
1. 【推荐】枚举类也存在与静态变量类似的问题,建议改动办法如下:
比如有这样的一个枚举类:
public enum StateEnum {
PASS("1", "通过"),
NOT_PASS("2", "不通过");
private String code;
private String name;
StateEnum(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
}用转换工具处理后,变成:
public enum StateEnum {
PASS("1",ResManager.loadKDString("通过", "StateEnum_0", "helloworld")),
NOT_PASS("2",ResManager.loadKDString("不通过", "StateEnum_1", "helloworld"));
private String code;
private String name;
StateEnum(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
}但枚举类按照Java规范也只会初始化加载一次。如果切换语言,则不会根据当前登录或显示语言加载相应的译文。
改动办法:新增一个类(类名请命名为:MultiLan
多语言开发规范
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。



