JavaSpring项⽬国际化(i18n)详细⽅法与实例Spring国际化概述
国际化基本规则
国际化信息”也称为“本地化信息”,⼀般需要两个条件才可以确定⼀个特定类型的本地化信息,它们分别是“语⾔类型”和“国家/地区的类型”。如中⽂本地化信息既有中国⼤陆地区的中⽂,⼜有、中国⾹港地区的中⽂,还有新加坡地区的中⽂。Java通过java.util.Locale类表⽰⼀个本地化对象,它允许通过语⾔参数和国家/地区参数创建⼀个确定的本地化对象。
语⾔简称
简体中⽂(中国)zh_CN
繁体中⽂()zh_TW
繁体中⽂(中国⾹港)zh_HK
英语(中国⾹港)en_HK
英语(美国)en_US
英语(英国)en_GB
英语(全球)en_WW
英语(加拿⼤)en_CA
英语(澳⼤利亚)en_AU
英语(爱尔兰)en_IE
英语(芬兰)en_FI
芬兰语(芬兰)fi_FI
英语(丹麦)en_DK
丹麦语(丹麦)da_DK
英语(以⾊列)en_IL
希伯来语(以⾊列)he_IL
英语(南⾮)en_ZA
英语(印度)en_IN
英语(挪威)en_NO
英语(新加坡)en_SG
英语(新西兰)en_NZ
英语(印度尼西亚)en_ID
英语(菲律宾)en_PH
英语(泰国)en_TH
英语(马来西亚)en_MY
英语(阿拉伯)en_XA
韩⽂(韩国)ko_KR
⽇语(⽇本)ja_JP
荷兰语(荷兰)nl_NL
荷兰语(⽐利时)nl_BE
葡萄⽛语(葡萄⽛)pt_PT
葡萄⽛语(巴西)pt_BR
法语(法国)fr_FR
法语(卢森堡)fr_LU
法语(瑞⼠)fr_CH
法语(⽐利时)fr_BE
法语(加拿⼤)fr_CA
西班⽛语(拉丁美洲)es_LA
西班⽛语(西班⽛)es_ES
西班⽛语(阿根廷)es_AR
西班⽛语(美国)es_US
西班⽛语(墨西哥)es_MX
西班⽛语(哥伦⽐亚)es_CO
西班⽛语(波多黎各)es_PR
德语(德国)de_DE
德语(奥地利)de_AT
德语(奥地利)de_AT
语⾔简称
德语(瑞⼠)de_CH
俄语(俄罗斯)ru_RU
意⼤利语(意⼤利)it_IT
希腊语(希腊)el_GR
挪威语(挪威)no_NO
匈⽛利语(匈⽛利)hu_HU
⼟⽿其语(⼟⽿其)tr_TR
捷克语(捷克共和国)cs_CZ
斯洛⽂尼亚语sl_SL
波兰语(波兰)pl_PL
瑞典语(瑞典)sv_SE
西班⽛语(智利)es_CL
语⾔类型判断
1)基于浏览器语⾔
根据Request Headers中的Accept-language来判断。
2)基于客户端传参
要求客户端第⼀次(或者每次)传递的⾃定义参数值来判断,如规定传locale,值为zh-cn、en-us等内容,如果只在第⼀次传⼊则local以及timeZone先关信息要存⼊session或者cookie中,后⾯的请求语⾔⽅式则直接从两者中取,其有效时间与session和cookie设置的⽣命周期关联。
3)基于默认配置
当获取语⾔类型时没有到对应类型时,会使⽤默认的语⾔类型。
语⾔类型保存
<!-- 定义本地化变更 -->
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInte
rceptor" />
<!-- 定义注解URL映射处理器,所有的请求映射关联本地化,或者也可⾃定义该路径映射-->
<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors" ref=" localeChangeInterceptor " />
<property name="order" value="1"></property>
</bean>
基于url
该种⽅式需要每次都在请求的url上带上local参数,指定该次需要的语⾔类型,并且该⽅式的local解析器需要配置,如下:
<a href="xxx.do?locale=zh_CN" rel="external nofollow" >中⽂</a>或<a href="xxx.do?locale=en" rel="external nofollow" >英⽂</a>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"/>
但在该配置下使⽤会抛Cannot change HTTP accept header - use a different locale resolution strategy异常,这是因为spring source做了限制,⽆法对本地的local赋值修改,解决办法如下,新建⼀个类MyLocaleResolver继承AcceptHeaderLocaleResolver,重写resolveLocale和setLocale⽅法,并将上⾯的localeResolver的class指向如下MyLocaleResolver类:
public class MyLocaleResolver extends AcceptHeaderLocaleResolver {
private Locale myLocal;
public Locale resolveLocale(HttpServletRequest request) {
return myLocal == null ? Locale() : myLocal;
}
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
myLocal = locale;
}
}
基于session
基于session的状态保存⽅式只需要在第⼀次请求的时候指定语⾔类型,localResolver会将该属性保存到session中,后⾯的请求直接从session中获取该语⾔类型,该种⽅式的localResolver对应的类为SessionLocaleResolver,如下配置:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
基于cookie
与session的机制类似,差异在于两者的存储和周期,鉴于安全、⼤⼩以及体验等因素的影响,实际使⽤中使⽤者更倾向于前者,该种cookie保存⽅式的localResolver为
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
⽂案数据来源
对于语⾔类型的资源⽂件,需要开发者对⽂案进⾏搜集整理,并翻译成相应的语⾔确定关键字key,⽬前⼤多数情况是将这些信息置
于.properties⽂件中,在使⽤的时候直接访问获取,当然也可置于数据库中,但频繁的⽂案获取会影响服务器性能及产品体验,可结合数据字典以及缓存⼯具使⽤。
数据库
1)spring 配置⽅式
<!-- 默认的注解映射的⽀持 -->
<mvc:annotation-driven validator="validator" conversion-service="conversionService" />
<!-- 资源⽂件 -->
<bean id="propertiesMessageSource" class="t.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>resource</value>
conversion翻译方法的定义<value>validation</value>
</list>
</property>
</bean>
<bean id="databaseMessageSource" class="com.obs2.util.MessageResource">
<property name="parentMessageSource" ref="propertiesMessageSource"/>
</bean>
<bean id="messageInterpolator" class="com.obs2.util.MessageResourceInterpolator">
<property name="messageResource" ref="databaseMessageSource"/>
</bean>
<!-- 验证器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator" ref="messageInterpolator"/>
</bean>
这⾥定义了⼀个propertiesMessageSource,⼀个databaseMessageSourcer,和⼀个messageInterpolator。propertiesMessageSource ⽤于读取properties⽂件databaseMessageSourcer⽤于读取数据库的数据配置,其中,有⼀个属性设置它的⽗MessageSource为propertiesMessageSource。意思是如果数据库不到对应的数据,到properties⽂件当中查。messageInterpolator是个。2)数据库的POJO定义
@Entity
@SuppressWarnings("serial")
@Table(name="resource")
public class Resource implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="resource_id")
private long resourceId;
@Column(name="name", length=50, nullable=false)
private String name;
@Column(name="text", length=1000, nullable=false)
private String text;
@Column(name="language", length=5, nullable=false)
private String language;
public long getResourceId() {
return resourceId;
}
public void setResourceId(long resourceId) {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getText() {
return text;
}
public void setText(String text) {
< = text;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}
定义了⼀张表[resource],字段有:[resource_id]、[name]、[text]、[language]。3)读取数据库的MessageResource类
/**
* 取得资源数据
* @author Robin
*/
public class MessageResource extends AbstractMessageSource implements ResourceLoaderAware { @SuppressWarnings("unused")
private ResourceLoader resourceLoader;
@Resource
private ResourceService resourceService;
/**
* Map切分字符
*/
protected final String MAP_SPLIT_CODE = "|";
protected final String DB_SPLIT_CODE = "_";
private final Map<String, String> properties = new HashMap<String, String>();
public MessageResource() {
reload();
}
public void reload() {
properties.clear();
properties.putAll(loadTexts());
}
protected Map<String, String> loadTexts() {
Map<String, String> mapResource = new HashMap<String, String>();
List<com.obs2.service.bean.Resource> resources = resourceService.findAll();
for (com.obs2.service.bean.Resource item : resources) {
String code = Name() + MAP_SPLIT_CODE + Language();
mapResource.put(code, Text());
}
return mapResource;
}
private String getText(String code, Locale locale) {
String localeCode = Language() + DB_SPLIT_CODE + Country();
String key = code + MAP_SPLIT_CODE + localeCode;
String localeText = (key);
String resourceText = code;
if(localeText != null) {
resourceText = localeText;
}else {
localeCode = Language();
key = code + MAP_SPLIT_CODE + localeCode;
localeText = (key);
if(localeText != null) {
resourceText = localeText;
}else {
try {
if(getParentMessageSource() != null) {
resourceText = getParentMessageSource().getMessage(code, null, locale);
}
} catch (Exception e) {
<("Cannot find message with code: " + code);
}
}
}
return resourceText;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
}
@Override
protected MessageFormat resolveCode(String code, Locale locale) {
String msg = getText(code, locale);
MessageFormat result = createMessageFormat(msg, locale);
return result;
}
@Override
protected String resolveCodeWithoutArguments(String code, Locale locale) {
String result = getText(code, locale);
return result;
}
}
主要是重载AbstractMessageSource和ResourceLoaderAware,以实现Spring MVC的MessageSource国际化调⽤。类中的reload()⽅法,我把它写到了⼀个ServletListener当中,让项⽬启动时,⾃动加载数据到static的map中。
4)Listener
/**
* 系统启动监听
* @author Robin
*/
public class SystemListener implements ServletContextListener {
/**
* context初始化时激发
*/
@Override
public void contextInitialized(ServletContextEvent e) {
// 取得ServletContext
ServletContext context = e.getServletContext();
WebApplicationContext applicationContext = WebApplicationContextUtils .getWebApplicationContext(context);
// 设置国际化多语⾔
MessageResource messageSource = Bean(MessageResource.class);
}
/**
* context删除时激发
*/
@Override
public void contextDestroyed(ServletContextEvent e) {
}
/**
* 创建⼀个 session时激发
* @param e
*/
public void sessionCreated(HttpSessionEvent e) {
}
/**
* 当⼀个 session失效时激发
* @param e
*
public void sessionDestroyed(HttpSessionEvent e) {
}
/**
* 设置 context的属性,它将激发attributeReplaced或attributeAdded⽅法
* @param e
*/
public void setContext(HttpSessionEvent e) {
}
/
**
* 增加⼀个新的属性时激发
* @param e
*/
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论