国际化开发规范
国际化不仅包含多语言翻译,还包含各地的使用习惯和习俗等。软件语言的切换选项在代码实现中的唯一标识符参照 语言标识列表。
为了保证用户体验和便于维护,特作出以下要求。
字符编码
因为语言不同,当存在多种编码的时候,应用展现层由于编码解析问题,容易造成乱码问题或者字符截断问题,故需要统一使用一种国际化的字符编码。
-
所有文本统一采用
UTF-8
编码后进行网络传输。 -
特殊字符必须进行转译后存入数据库(如
\
)。 -
对于会导出给用户编辑,而后再导入的文本文件,如
csv
等,统一使用 UTF-8 编码。
可视化界
-
软件安装或完成时,存在语言切换的选项(允许重启后生效)。
-
在未获取到多语言时(如:浏览器界面在首次加载时),预加载页面、浏览器标题等信息尽量避免使用文字,可显示为能表示在加载中的动图;必须使用文字的,显示
Loading
。 -
某些国家的语言(如德语、俄语等)翻译后的字符特别长,平均长度是英语的 1.5 到 2 倍,界面在显示文案时会因为超长字符出现破坏页面布局、样式或超长字符无法显示全的情况。
-
客户端界面所有文案在非中文环境下布局合理、样式正常,对于文案较长的情况,需要对文案进行缩略处理,同时增加
Title
提示,确保用户通过Title
可以查看到完整文案。 -
软件语言在切换后,重启浏览器或重启服务器的操作后仍要保留上次选择的语言。
-
尽量不直接使用带有文字的图片(图片来源是用户上传的除外),文字须是在无文字的图片上进行二次叠加的,保证图片中文字可翻译。
可视化文案信息处理
-
软件界面展示的文本字段需要以唯一的字符Key来标识文本字段。
-
字符 Key 与其对应的语言只允许增加,不允许修改与删除。
-
在软件通信传输过程中,不允许直接的文本传输(用户输入文本并写入数据库的除外),应将文本转换成翻译标识
Key
后再进行传输,由表示层进行翻译展示。
Key 规则如下:
-
字符 key 必须采用 ASCII 码编写,仅可包含【数字、英文字母、下划线(
_
)、中划线(-
)、英文句号(.
)】,尽量避免使 用容易产生混淆的组合,如 0 和 1,两者与小写英文字母 o 和 l 。 -
Key 最大长度限制为 128 位。
-
代码中只能使用字符
Key
,展示层负责翻译显示。 -
在代码、脚本等文件中除注释外,不应存在任何的特定语言文本信息(如:中文),涉及的文件类型包含但不仅限于:.java、.js、.json、.properties、.sql、.vue、.html、.xml、.ui、.h、.cpp 等。
-
不允许用多个
Key
来拼接组成词或句子,语法不一定正确。 -
用于界面显示的多语言
Key
包含三部分组成,格式定义为<应用标识>.<i18nKey>.<类型标识>
。
类型 | 标识 | 说明 |
---|---|---|
名称 |
name |
名词短语,如:name、label、tab、menu、type 等。 |
句子 |
msg |
描述语句,如 msg、desc(description)、intro(introduction)、info(information)、sug(suggestion)、warn(warning) 等。 |
按钮 |
button |
动词短语,如 btn(button)。 |
时间、时区国际化
时间格式可配置,如 周起止时间
、 显示样式
-
默认时间格式选用
ISO 8601
标准时间格式。-
带时区:
yyyy-MMdd<T>HH:mm:ss.sss[+|-]hh:mm
-
不带时区:
yyyy-MM-dd<T>HH:mm:ss.sssZ
-
-
传输、存储时采用默认格式,终端展示时允许修改格式。
编码和使用 [1]
-
合理利用请求上下文、线程上下文保存语言标识,避免在业务方法入参中包含业务无关的参数。
[[Java 中创建语言标识方式]]
// 带有语言和国家/地区信息的本地化对象
Locale locale1 = new Locale("zh","CN");
// 只有语言信息的本地化对象
Locale locale2 = new Locale("zh");
// 等同于Locale("zh","CN")
Locale locale3 = Locale.CHINA;
// 等同于Locale("zh")
Locale locale4 = Locale.CHINESE;
// 获取本地系统默认的本地化对象
Locale locale5 = Locale.getDefault();
JDK 中提供了几个支持本地化的格式化操作工具类:
-
NumberFormat
-
NumberFormat.getCurrencyInstance(Locale.CHINA).format(xxx); (
¥123,456.78
)
-
-
DateFormat
-
MessageFormat
[[MessageFormat 的使用]]
// 信息格式化串
String pattern1 = "{0},你好!你于{1}在工商银行存入{2} 元。";
String pattern2 = "At {1,time,short} On{1,date,long},{0} paid {2,number, currency}.";
// 用于动态替换占位符的参数
Object[] params = {"John", new GregorianCalendar().getTime(),1.0E3};
// 使用默认本地化对象格式化信息
String msg1 = MessageFormat.format(pattern1,params);
// 使用指定的本地化对象格式化信息
MessageFormat mf = new MessageFormat(pattern2,Locale.US);
String msg2 = mf.format(params);
System.out.println(msg1);
System.out.println(msg2);
输出如下
John,你好!你于07-1-8 下午9:58在工商银行存入1,000元。 At 9:58 PM OnJanuary 8, 2007,John paid $1,000.00. ResourceBoundle
如果应用系统中某些信息需要支持国际化功能,则必须为希望支持的不同本地化类型分别提供对应的资源文件,并以规范的方式进行命名。 国际化资源文件的命名规范规定资源名称采用以下的方式进行命名:
<资源名><语言代码><国家/地区代码>.properties
-
语言代码和国家/地区代码都是可选的。
-
<资源名>.properties
命名的国际化资源文件是默认的资源文件(某个本地化类型在系统中找不到对应的资源文件,就采用这个默认的资源文件)。 -
<资源名>_<语言代码>.properties
命名的国际化资源文件是某一语言默认的资源文件,即某个本地化类型在系统中找不到精确匹配的资源文件,将采用相应语言默认的资源文件。 -
不同语言的同一资源文件,
value
(属性值)不同,但key
(属性名)相同,这样应用程序就可以通过Locale
和特定的key
来找到对应语言翻译后的value
。 -
文件内容 只能 包含
ASCII
字符。
由于直接采用Unicode代码编辑资源文件是很不方便的,所以,通常我们直接使用正常的方式编写资源文件,在测试或部署时再采用工具进行转换。
JDK 在 bin
目录下为我们提供了一个完成此项功能的 native2ascii
工具,它可以将中文等资源文件转换为 Unicode
代码格式的文件,命令格式如下:
native2ascii [-reverse] [-encoding 编码] [输入文件 [输出文件]]
-
把
UTF-8
格式的多语言资源文件resource_zh_CN.properties
转为 ASCII 资源文件-
native2ascii -encoding utf-8 d:\resource_zh_CN.properties
即可得到d:\resource_zh_CN_1.properties
-
该命令还是不方便,主流 IDE
中一般自带转换。
常用多语言工具类介绍
JDK 的 ResourceBundle
如果应用程序中拥有大量的本地化资源文件,直接通过传统的 File
操作资源文件显然太过笨拙。Java为我们提供了用于加载本地化资源文件的方便类 java.util.ResourceBoundle
。
-
从相对于类路径的目录中加载一个名为
resource
的本地化资源文件,并获取对应的属性值-
ResourceBundle rb = ResourceBundle.getBundle("org/shoulder/i18n/resource", locale)
-
rb.getString("greeting.common")
-
-
只允许指定类路径下的资源文件
-
如果指定的本地化资源文件不存在,它按以下顺序尝试加载其他的资源
-
系统默认本地化对象对应的资源
-
不带语言/地区标识的资源文件
-
Spring 中的 MessageSource
三个用法(详见其注释)
-
解析code对应的信息进行返回,如果对应的code不能被解析则返回默认信息defaultMessage。
-
解析code对应的信息进行返回,如果对应的code不能被解析则抛出异常NoSuchMessageException
-
通过传入的
MessageSourceResolvable
对应来解析对应的信息
它被 HierarchicalMessageSource
和 ApplicationContext
接口扩展,AbstractApplicationContext 中实现了
AbstractApplicationContext#initMessageSource()
做 MessageSource
的初始化工作
Spring 中提供的三个实现类
-
StaticMessageSource
-
主要用于程序测试,它允许通过编程的方式提供国际化信息。
-
-
ResourceBundleMessageSource
-
基于JDK ResourceBundle,会将访问过的ResourceBundle缓存起来,以便于下次直接从缓存中获取进行使用
-
cacheSeconds
-
-
ReloadableResourceBundleMessageSource
-
基于
PropertiesPersister
来加载对应的文件,使用java.util.Properties来保存对应的数据(即可包括properties
xml
文件)。 -
允许指定非类路径下的文件作为对应的资源文件,可以使用 Spring支持的资源文件的前缀,如
classpath:
、file:
、http:
、ftp:
等 footnote[Spring 支持的资源文件加载方式, https://blog.csdn.net/hulei19900322/article/details/75200356] -
cacheSeconds
提供了定时刷新功能,允许在不重启系统的情况下,更新资源的信息。
-
-
SpringSecurityMessageSource
-
The default MessageSource used by Spring Security.
-
