1. 设计原由
由于JFinal的国际化(I18N)支持在JSP中支持不好,因此,萌生了解决这一短板的念头。
实现时也考虑了几种方式,最终决定采用JSP中最原始的标签。因为自定义标签在JSP中容易实现,内容灵活且功能比较强大,可扩展性好。
2. I18N标签
自定义的I18N标签需要针对I18N的各个接口做最好的支持,使用<jf:i18n />作为标签名,下面是JFinal中I18N类的几个接口:
public static String getText(String key)
public static String getText(String key, String defaultValue)
public static String getText(String key, Locale locale)
public static String getText(String key, String defaultValue, Locale locale)
完整的标签被设计成:
<jf:i18n key="" defaultValue="" locale="" paras="" />
参数说明:
参数名 | 作用 | 说明 |
key | 对应接口中的key |
|
defaultValue | 对应接口中的defaultValue |
|
locale | 对应接口中的locale | 数据类型有差别,这里只能使用字串,如:zh_CN, en_US |
paras | 全新的属性,为了支持参替换而设计 | 1.假如key对应字串为“早上好!{0}们,现在正实验{1}。”;paras取值为“小白,I18N标签”(参数间用逗号隔开);那么得到的最终结果是“早上好!小白们,现在正实验I18N标签。” 2.另外,参数可以从Controller的attr中取值,例如:Controller中setAttr(“p1”, “小白”).setAttr(“p2”, “I18N标签”);标签中的paras取值为“p1,p2”,寻么最终结果还是“早上好!小白们,现在正实验I18N标签。” |
3. 代码实现
3.1 I18nTag.java
package com.jfinal.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import com.jfinal.i18n.I18N;
import com.jfinal.kit.LocaleKit;
import com.jfinal.kit.StringKit;
/**
* JSP页面中用于支持I18N的标签。
*/
public class I18nTag extends TagSupport {
private static final long serialVersionUID = -8073376431317433802L;
/**
* I18N中的key值
*/
private String key;
/**
* 当key值不存在时使用的默认值
*/
private String defaultValue;
/**
* 地区属性,如:zh_CN, en_US
*/
private String locale;
/**
* 作为value格式化值使用的参数,多个用逗号隔开,如果参数值在Request中有对应的attribute,则取attribute值
*/
private String paras;
@SuppressWarnings("deprecation")
@Override
public int doStartTag() throws JspException {
// if (StringKit.isBlank(this.getKey())) {
// throw new JspException("The tag attribute of key is not exists.");
// }
// 定义输出给页面的text
String text = null;
try {
if (StringKit.isBlank(locale)) {
// 通过I18N接口拿到值
text = I18N.getText(key, this.defaultValue);
} else {
// locale定义了值,说明指定了前端要显示的语言类型,语言类型交由LocaleKit处理
text = I18N.getText(key, this.defaultValue, I18N.localeFromString(locale));
}
} catch (Exception e) {
text = defaultValue;
}
if (StringKit.notBlank(paras)) {
// 如果tag中指定了paras,则将paras解析为array
String[] attrs = paras.split(",");
Object[] values = new Object[attrs.length];
// 循环将参数到Request中取值,如果有值,则替换
for (int i = 0; i < attrs.length; i++) {
String a = attrs[i];
values[i] = pageContext.getRequest().getAttribute(a) == null ? attrs[i] : pageContext
.getRequest().getAttribute(a);
}
pageContext.getAttribute("");
text = String.format(text, values);
}
try {
// 将结果输出到页面
pageContext.getOut().write(text);
} catch (IOException e) {
return Tag.SKIP_BODY;
}
return Tag.EVAL_BODY_INCLUDE;
}
public String getKey() {
return this.key;
}
public void setKey(String key) {
this.key = key;
}
public String getDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public String getLocale() {
return this.locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getParas() {
return this.paras;
}
public void setParas(String paras) {
this.paras = paras;
}
3.2 Jfinal.tld
文件与I18nTag.java放在同一目录下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>bean</shortname>
<uri>http://www.jfinal.com/tag</uri>
<tag>
<name>i18n</name>
<tagclass>com.jfinal.tag.I18nTag</tagclass>
<bodycontent>JSP</bodycontent>
<attribute>
<name>key</name>
<required>true</required>
<rtexprvalue></rtexprvalue>
</attribute>
<attribute>
<name>defaultValue</name>
<required>false</required>
<rtexprvalue></rtexprvalue>
</attribute>
<attribute>
<name>paras</name>
<required>false</required>
<rtexprvalue></rtexprvalue>
</attribute>
<attribute>
<name>locale</name>
<required>false</required>
<rtexprvalue></rtexprvalue>
</attribute>
</tag>
</taglib>
4. Tag的使用
4.1 定义多国语言属性文件
myi18n_en_US.properties
greeting=Today is %2$s/%3$s/%1$s
myi18n_zh_CN.properties
greeting=今天是%1$s年%2$s月%3$s日
4.2 启动时加载I18
在JFinalConfig.configConstant(Constants me)中加入如下代码:
// 载入I18N文件
me.setI18n("myi18n", Locale.SIMPLIFIED_CHINESE, Integer.MAX_VALUE);
4.3 在Controller中设置属性
Calendar c = Calendar.getInstance();
c.setTime(new Date());
this.setAttr("yyyy", c.get(Calendar.YEAR));
this.setAttr("MM", c.get(Calendar.MONTH) + 1);
this.setAttr("dd", c.get(Calendar.DAY_OF_MONTH));
4.4 JSP页面中定义标签
<%@ taglib prefix="jf" uri="/WEB-INF/classes/com/jfinal/tag/jfinal.tld"%>
<h5><jf:i18n key="non_key" defaultValue="没有key值显示我" paras="2014,7,8" /></h5>
<h5><jf:i18n key="greeting" defaultValue="没有key值显示我" paras="2014,7,8" locale="zh_CN"/></h5>
<h5><jf:i18n key="greeting" defaultValue="没有key值显示我" paras="2014,7,8" locale="en_US" /></h5>
<h5><jf:i18n key="greeting" defaultValue="没有key值显示我" paras="yyyy,MM,dd" locale="en_US" /></h5>
首先引入标签,引入的是标签定义文件tld的位置,编译后,tld的位置为"/WEB-INF/classes/com/jfinal/tag/jfinal.tld",它也是目标位置。
4.5 执行结果
5. 问题
细心的读者可能已经发现了,paras参数是为替换{0},{1}这类型参数,结果却替换了%1$s年%2$s这样的参数。这是因为代码使用String.format()格式化,却不知为什么不能支持{0},{1}。作者没时间去探究,哪位读者有时间帮我找出答案吧。