昨天到新公司,刚来老板就让把他们之前总的项目搞个国际化。
因为觉得所有的jsp的属性文件都写到一个文件里会导致文件过大且难以维护,key值也不好设计。所以没有使用struts2的常用国际化方式
而是选择了自己写一个tag并用resourcebundle实现国际化文件的分割,和命名空间的一个效果。这样可以重复使用相同的key。
不费话了,上代码。如果有高人指点,希望指出优化方法,或者struts2有没有类似的应用。
1 加web.xml中
<!-- 自定义标签,用于国际化 -->
<jsp-config>
<taglib>
<taglib-uri>http://sjim/te</taglib-uri>
<taglib-location>/WEB-INF/tld/TE.tld</taglib-location>
</taglib>
</jsp-config>
其中taglib-location时tld文件的物理位置,而taglib-uri则为在jsp中导入时引用的uri,可以自己定义。
2 TE.tld文件写好
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>TETagLibrary</short-name>
<uri>/TETagLibrary</uri>
<tag>
<name>text</name>
<tag-class>com.sj.te.util.tag.TETag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>path</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>key</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
tld的定义我用的不多,这里的uri无效,被web.xml中的配置覆盖掉了。如果web.xml中不进行配置,可以使用这里的uri进行jsp导入。
tag标签中定义的是方法,name为方法名,tag可以定义多个。我这里只需要完成资源获取功能,因此只配了text一个方法。
tag-class为实现该方法的类,该类必须继承SimpleTagSupport类。
attribute为方法的参数,这里path为资源路径,key为要选取的键值对。
3 实现com.sj.te.util.tag.TETag类,以下为代码
package com.sj.te.util.tag;
import java.io.IOException;
import java.util.Locale;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import com.sj.te.util.TEResourceUtil;
public class TETag extends SimpleTagSupport{
private String path;
private String key;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public void doTag() throws JspException, IOException {
String value = null;
JspContext jc = this.getJspContext();
PageContext pc = (PageContext)jc;
Locale l = (Locale)pc.getSession().getAttribute("locale");
if(!l.equals(Locale.US) && !l.equals(Locale.CHINA)){
l = Locale.CHINA;
}
value = TEResourceUtil.getString(path, key, l);
JspWriter out = pc.getOut();
out.print(value);
}
}
该类中的核心方法为doTag()方法,我在这里获取了path和key之后,还获取了当前page中的语言设置,将这三个参数传给 TEResourceUtil中的静态方法getString(path, key, l)以获取返回值value,而value则为最终要显示的国际化信息
使用JspWriter进行写出。
4 TEResourceUtil代码
package com.sj.te.util;
import java.util.Locale;
import java.util.ResourceBundle;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
public final class TEResourceUtil {
private static String rootPath;
static {
rootPath = "resource";
try {
Class.forName("com.opensymphony.xwork2.util.LocalizedTextUtil");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public TEResourceUtil() {
}
public static ResourceBundle getResourceBundle(String baseName,Locale l){
String path = rootPath+"/"+baseName;
return LocalizedTextUtil.findResourceBundle(path, l);
}
public static String getString(String baseName, String key, Locale l) {
String result = null;
try{
result = getResourceBundle(baseName, l).getString(key);
} catch (Exception e) {
return "<div style='color:red'>Matching Exception:"+key+"</div>";
}
return result;
}
}
静态初始化块儿中先定义了所有资源的根目录resource,这样比较规范
然后加载了一个类com.opensymphony.xwork2.util.LocalizedTextUtil,这个类是resourcebundle实现的主要类
getResourceBundle使用LocalizedTextUtil根据传进来的baseName和locale来返回相应的资源文件,如果内存中没有则新建
如果有则直接返回。
getResourceBundle中获得返回的ResourceBundle之后,使用其中的getString(key)来得到属性文件中相应的value
如果找到则返回找到的value,如果没有找到则返回错误信息并打印在相应位置。
到此,简单的实现方法就写完了。当然jsp我没有给出,资源文件也没有贴。稍微有些国际化知识的人应该都能看懂。
最后再贴一个我写好的使用规范
使用TAG实现国际化
1. 在src文件夹下的resource(所有国际化资源文件都在这里)文件夹中创建自己的国际化文件,可以放在自己新建的文件夹中并自己命名(但是必须记住自己的资源文件的路径以便jsp中调用)
资源文件命名规则XXX_zh_CN.properties,XXX_en_US.properties。XXX为自定义basename
则当前两个文件路径为resource/../…./ XXX_zh_CN.properties A
以及resource/../…./ XXX_en_US.properties B
此二文件为中英文资源文件,如有需要可以继续添加其他语种。
2. 在jsp(使用1中定义好的资源文件)中
首先添加新的标签 <%taglib prefix=”te” uri=”http://sjim/te”%>
标签用法
当 1中A,B为resource/path1/path2/ XXX_zh_CN.properties
和resource/path1/path2/ XXX_en_US.properties
且A,B属性文件内容包括KEY1=值1
和KEY1=value1
时。
提取数据写法为<te:text path=”path1/path2/XXX” key=”KEY1”>