多么悲哀的一天呀!偶在庆幸破解Jive Forums 3.0.9 同时,决定要把这个好东东用在自己公司的网站中,于是呼又一次可怕的经历伴随我度过了一个充满挫折与气馁的晚上,5555555555555,在梦中???伴随着偶,可怕的JAVA中文显示问题呀!
我们在使用Jive Forums的时候不可能让他一直用E文的菜单与内容。还好,这个东东实在是太厉害了,偶在折腾Jive Forums的几天中深刻的被他那完善与清晰的设计路线所倾倒,太可怕了,也不知道老外的脑袋是怎么长的,在佩服之余偶在想如何汉化的他的道路。
下面就说一说Jive Forums的完全汉化工作
第一步:Jive Forums内容的中文化:
我看Jive Forums在设计的时候已经充分考虑过此问题,那就是针对多种语言的考虑,在Jive Forums中我们能够感受到XML的充分使用,所有的配置全部都是以XML为基础,而且在结构上也进行了另人高兴的考虑,他的内容中文化是比较简单。
在安装完Jive Forums后,在系统管理界面中有两个地方需要修改,第一,是在Global Settings 下的Locale Settings中有一个Change Locale Settings 选项,我们在Locale:中肯定选中国了,在Time Zone:中一定选GMT+8:0 ASIA SHANGHAI CST,在Character Set:下选择User Specified:在其中输入GB2312 或 GBK 都可以,偶一般用GB2312,这一步就算完成了,是不是很简单。
第二,是在Global Features中选择Search Settings,这个选项是你搜索时使用的配置,在Search Indexing Settings下选择Indexer Type:中的DOUBLE-BYTE (ASIAN LANGUAGES)以便支持中文的搜索功能。
以上这两步作完后,还有一步要进行,那就是修改你的jive_config.xml在这个XML中<database>
<defaultProvider>
<driver>org.gjt.mm.mysql.Driver</driver>
<serverURL>jdbc:mysql://localhost:3306/jive3</serverURL>
<username>root</username>
<password>6616</password>
<minConnections>5</minConnections>
<maxConnections>10</maxConnections>
<connectionTimeout>1.0</connectionTimeout>
</defaultProvider>
这后面添加对UNICODE的支持:
<mysql>
<useUnicode>true</useUnicode>
</mysql>
</database>
我用的MYSQL,但其他数据库用不用加,看安装说明就可以了,这个地方的修改在说明中有。
呵呵。。。上面这些工作完成以后,就可以进行Jive Forums的其他配置了,比如添加类别,版块什么的,新加的内容就应该是中文的了,不用修改任何TOMCAT的配置。
注意:如果你在以上修改以前如果添加的中文内容,即使修改后也不能显示正常,需要删除后从新添加!因为那时侯使用的是E文字符集ISO-8859-1,而添加后的内容在数据库中就已经被转成了乱码。
好了, 现在光有了中文内容恐怕还不够,要想用一个完美的Jive Forums应该是所有界面都是中文的吧!
不用着急咱们漫漫的来,偶在做这一步之前一直以为不就是汉化JSP页面吗?实在是简单,简单的都另偶失去修改的欲望,觉得这是美工的任务,偶这种垃圾程序员怎么能去做如此低级的工作呢!
但是偶这个错误犯的实在太大了,如果你让美工去汉化JSP页面也许能用,但是,会把他给累死不说,还可能把Jive Forums给修改死掉,因为这个Jive Forums实在太可怕了,偶现在想想还在发抖呢!
现在就说说彻底的Jive Forums汉化吧!
第二步工作:
Jive Forums的设计决定着他的强大,在JSP的代码中就充分体现出来,在JSP中我们会看到<jive:i18n key="global.category" /><jive:i18n key="global.colon" />此类引用的文字,Jive Forums竟然也把界面相关的文字内容使用最模块化的方法进行维护,在jivebase.jar与jiveforums.jar这两个包中相关的.properties文件可以很容易找到,上面在JSP界面中的引用单词或句子就是在这些.properties中定义的,当然了咱们也可以修改了,嘿嘿。。。。。
这就是这些.properties中的一些内容:
global.post_reply=发布新的回复
global.previous_page=前一页
global.remember_me=记住自己
global.replies_to_this_message=回复这个信息
global.search_forum=搜索论坛
global.the_forum_you_posted_in=The forum you posted in
global.the_last_page_you_visited=The last page you visited.
global.the_main_forums_page=The main forums page
global.the_message_you_created=The message you created
global.the_topic_you_created=The topic you created
global.the_topic_you_posted_in=The topic you posted in
好象这招比较狠毒一样,在得意中的我失败了!偶在修改完一些.properties后,从新打包成JAR后,运行的结果使偶非常气馁,因为改过的E文,在成为中文后都变成???了,偶开始还觉得是不是JSP页面的字符集问题,可是不对,我添加的版块,类别什么的东东中文都能显示,为何修改后的.properties中E对照就不行呢!我苦恼着,想了半天多,累了就睡一会,可是在梦中又被那张牙舞爪的???给惊醒。
偶没有放弃但经过N次尝试后还是不能解决,我一直怀疑JPS页面的原因终于放弃了,经过多方查找与思考,我判断应该是在这些.properties文件中对照变量的读取中出现了问题,而在jiveforums包中竟然有法文与意大利文的.properties文件,他们内容同jive_i18n.properties一样只不过是对应了不同的语言而已,看来Jive还没有准备给中国人们使用!他根本就没有想过中文界面,看来只有自己解决的。
于是偶冒着失落痛苦的折磨,在失去斗志的心理下进行了痛苦的反编译工作。偶在苦难中徘徊,一次又一次的失败使偶本来就不足的信心崩溃了,我放下手中的工作,抱起在床上"咿呀,咿呀"的小侄女,呵呵。。。偶现在失业在家做临时保姆,没事的时候带带孩子放松放松。
她七个月大,在我的怀中她也不知想说什么,但是我却感到她不会放弃的精神是如此的强烈,她一次次的伸手来抓我本本上的网卡辫子,偶也一次次的阻挠她,但是她丝毫没有放弃,还是那么的前进着,偶心中有一点触动,这是什么?难道孩子明白的道理,我一个快27的大人不明白吗?困难算什么?我不前进这些所谓的困难就一直是我的困难,而过去困难还是困难吗?
偶醒了,抖擞精神的我,从新开始了艰难的分析工作,终于我找到了问题的所在,一个JAVA的老毛病,也就是Jive Forums在从.properties中取值的时候一定没有考虑过中文字符,而是使用默认的ISO-8859-1进行取值,所以才会出现???的结果,偶就查找了JSP页面中的一些代码,发现是这些值的取得使用了com\jivesoftware\util\LocaleUtils.class这个类,偶用JAD反编译后才知道自己是找对了地方,以前一直徘徊在BASE下的一些CLASS中。
于是偶就从新开始分析此CLASS,找到了问题得根源,哈哈。。。得意的受不了!原来在这个CLASS中根本没有想过中文的处理,偶就在这个CLASS中添加了一个转换的函数,在其返回函数值的时候给转换一下,就OK了。
下面是偶添加修改后的代码:
package com.jivesoftware.util;
import com.jivesoftware.base.*;
import java.text.*;
import java.util.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import com.jivesoftware.base.JiveGlobals;
// Referenced classes of package com.jivesoftware.util:
// CookieUtils
public class LocaleUtils
{
private LocaleUtils()
{
}
public static Locale localeCodeToLocale(String localeCode)
{
Locale locale = null;
if(localeCode != null)
{
String language = null;
String country = null;
String variant = null;
if(localeCode != null)
{
StringTokenizer tokenizer = new StringTokenizer(localeCode, "_");
if(tokenizer.hasMoreTokens())
{
language = tokenizer.nextToken();
if(tokenizer.hasMoreTokens())
{
country = tokenizer.nextToken();
if(tokenizer.hasMoreTokens())
variant = tokenizer.nextToken();
}
}
}
locale = new Locale(language, country == null ? "" : country, variant == null ? "" : variant);
}
return locale;
}
public static String[][] getTimeZoneList()
{
if(timeZoneList == null)
synchronized(timeZoneLock)
{
if(timeZoneList == null)
{
Date now = new Date();
String timeZoneIDs[] = TimeZone.getAvailableIDs();
Locale jiveLocale = JiveGlobals.getLocale();
timeZoneList = new String[timeZoneIDs.length][2];
for(int i = 0; i < timeZoneList.length; i++)
{
String zoneID = timeZoneIDs[i];
timeZoneList[i][0] = zoneID;
timeZoneList[i][1] = getTimeZoneName(zoneID, now, jiveLocale);
}
}
}
return timeZoneList;
}
public static Locale getUserLocale(HttpServletRequest request, User user)
{
Locale locale = null;
if(user != null)
{
if("true".equals(JiveGlobals.getJiveProperty("skin.default.usersChooseLocale")))
{
Locale userLocale = localeCodeToLocale(user.getProperty("jiveLocale"));
if(userLocale != null)
locale = userLocale;
}
} else
if("true".equals(JiveGlobals.getJiveProperty("skin.default.usersChooseLocale")))
{
Cookie cookie = CookieUtils.getCookie(request, "jiveLocale");
if(cookie != null)
{
Locale userLocale = localeCodeToLocale(cookie.getValue());
if(userLocale != null)
locale = userLocale;
}
}
if(locale != null)
return locale;
else
return JiveGlobals.getLocale();
}
public static TimeZone getTimeZone(HttpServletRequest request, User user)
{
TimeZone timeZone = JiveGlobals.getTimeZone();
String timeZoneID = null;
if(user != null)
{
timeZoneID = user.getProperty("jiveTimeZoneID");
} else
{
Cookie cookie = CookieUtils.getCookie(request, "jiveTimeZoneID");
if(cookie != null)
timeZoneID = cookie.getValue();
}
if(timeZoneID != null)
timeZone = TimeZone.getTimeZone(timeZoneID);
return timeZone;
}
private static String getTimeZoneName(String zoneID, Date now, Locale locale)
{
TimeZone zone = TimeZone.getTimeZone(zoneID);
StringBuffer buf = new StringBuffer();
int offset = zone.getRawOffset();
if(zone.inDaylightTime(now) && zone.useDaylightTime())
offset += 0x36ee80;
if(offset < 0)
buf.append("GMT-");
else
buf.append("GMT+");
offset = Math.abs(offset);
int hours = offset / 0x36ee80;
int minutes = (offset % 0x36ee80) / 60000;
buf.append(hours).append(":");
if(minutes < 10)
buf.append("0").append(minutes);
else
buf.append(minutes);
buf.append(" - ").append(zoneID.replace('_', ' ').replace('/', ' ')).append(" ");
buf.append(zone.getDisplayName(true, 0, locale).replace('_', ' ').replace('/', ' '));
return buf.toString();
}
public static ResourceBundle getResourceBundle(String baseName, Locale locale)
{
return ResourceBundle.getBundle(baseName, locale);
}
//偶添加的中文转换函数
public static String toChinese(String strvalue)
{
try{
if(strvalue==null)
return null;
else
{
strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
return strvalue;
}
}catch(Exception e){
return null;
}
}
public static String getLocalizedString(String key)
{
return getLocalizedString(key, JiveGlobals.getLocale(), null);
}
public static String getLocalizedString(String key, Locale locale)
{
return getLocalizedString(key, locale, null);
}
public static String getLocalizedString(String key, List arguments)
{
return getLocalizedString(key, JiveGlobals.getLocale(), arguments);
}
public static String getLocalizedString(String key, Locale locale, List arguments)
{
if(key == null)
throw new NullPointerException("Key cannot be null");
if(locale == null)
locale = JiveGlobals.getLocale();
String value = "";
ResourceBundle bundle = ResourceBundle.getBundle("jive_i18n", locale);
try
{
value = bundle.getString(key);
}
catch(MissingResourceException mre)
{
Log.error("Missing resource for key: " + key + " in locale " + locale.toString());
value = "";
}
if(arguments != null)
{
MessageFormat messageFormat = new MessageFormat("");
messageFormat.setLocale(bundle.getLocale());
messageFormat.applyPattern(value);
try
{
java.text.Format formats[] = messageFormat.getFormats();
for(int i = 0; i < formats.length; i++)
{
java.text.Format format = formats[i];
if(format != null)
if(format instanceof DateFormat)
{
if(arguments.size() > i)
{
Object val = arguments.get(i);
if(val instanceof String)
{
DateFormat dateFmt = (DateFormat)format;
try
{
val = dateFmt.parse((String)val);
arguments.set(i, val);
}
catch(ParseException e)
{
Log.error(e);
}
}
}
} else
if((format instanceof NumberFormat) && arguments.size() > i)
{
Object val = arguments.get(i);
if(val instanceof String)
{
NumberFormat nbrFmt = (NumberFormat)format;
try
{
val = nbrFmt.parse((String)val);
arguments.set(i, val);
}
catch(ParseException e)
{
Log.error(e);
}
}
}
}
value = messageFormat.format(((Object) (arguments.toArray())));
}
catch(IllegalArgumentException e)
{
Log.error("Unable to format resource string for key: " + key + ", argument type not supported");
value = "";
}
}
return toChinese(value); //偶修改的地方
}
public static String getLocalizedNumber(long number)
{
return NumberFormat.getInstance().format(number);
}
public static String getLocalizedNumber(long number, Locale locale)
{
return NumberFormat.getInstance(locale).format(number);
}
public static String getLocalizedNumber(double number)
{
return NumberFormat.getInstance().format(number);
}
public static String getLocalizedNumber(double number, Locale locale)
{
return NumberFormat.getInstance(locale).format(number);
}
private static String timeZoneList[][] = null;
private static Object timeZoneLock = new Object();
private static final String resourceBaseName = "jive_i18n";
}
哈哈。。。偶加了一个toChinese的函数,是在网上抄的,嘿嘿。。。。
然后在getLocalizedString函数返回值时转化了一下,就是这里return toChinese(value);就这样偶用JBUILDER8 从新编译了该CLASS,用JAR从新打包后,覆盖了原来的JAR包,运行TOMCAT后就出现了我可爱的中文。
总结:做任何事情遇到困难是最正常不过的,只有在重重困难下,我的生活才显得无比可爱与美好,而事物的两面性是我们分析问题解决问题的基础,当我们在动过脑子,冷静下来后,问题的解决方法总是可爱的跳到我们面前,原来我们的问题是因为我们的无知才出现的,兄弟姐妹们用平和的心态来看待这个世界,那点点滴滴都是那么的美好与可爱,嘿嘿。。。还好偶已经不做IT了。