`
cloudtech
  • 浏览: 4578543 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

Spring MVC+Freemarker+Javascript的多语言(国际化i18n/本地化)和主题(Theme)实现

 
阅读更多

http://www.cnblogs.com/Mainz/archive/2012/08/04/2622858.html

http://www.iteye.com/topic/1121801

导语

本文说说java web的多语言国际化实现和主题(Theme)的实现,具体到框架是Spring MVC+Freemarker+jQuery/JS的多语言国际化实现和主题(Theme)的实现。如果一个系统会被多个国家使用,则多语言国际化/本地化是必须的。其实多语言只是国际化(i18n)的一部分,国际化(i18n)/本地化(l10n)(Wiki:Internationalization and localization)还包括货币、时区、符号、格式等其它内容。每种语言基本都支持国际化,比如.NET, php都支持,当然java也一样。Java是一种基于Unicode的编程语言,提供了资源绑定(ResourceBundle)、地区(Locale)、时区(Timezone)等支持国际化。本文只说多语言(Multi-language)和主题(Theme)的实现。由于多语言散布在html、jsp、freemarker/*.frl、controller/Spring MVC、和javascript/js中,所以我们需要实现的是一个整体解决方案。本文内容:

  1. Java的资源国际化
  2. ResourceBundle类
  3. Servlet和Spring访问资源文件
  4. Servlet和多语言
  5. Spring MVC+Freemarker+jQuery/js的多语言实现
  6. jFreeReport的多语言国际化
  7. jqGrid的多语言/国际化/i18n实现
  8. jQuery.UI.DatePicker的多语言/国际化/i18n实现
  9. Spring mvc的主题Theme实现

Java的资源国际化

Java默认的资源文件为*.properties(例如:messages_en_US.properties),资源文件要放到相应的classPath下面,和java一起编译。资源文件里面的内容是key/value的格式,比如:hello = hello, world. 资源文件的编码是UTF-8,也就是说里面可能不是直接要显示的文字,而是UTF-8编码以后的内容。properties里面的资源必须经过编码,不允许里面出现法文、德文、中文、日文等Unicode字符,而必须是ASCII字符。UnicodeASCII可以使用JSK自带的native2ascii.exe工具,位于JDK安装目录的bin目录下,双击运行,输入中午或日文或法文,格式:native2ascii -[options] [inputfile [outputfile]],例如:native2ascii -encoding UTF-8 c:\message_de_DE.txt c:\message_de_DE.properties,回车开始转换。

ResourceBundle类

JSP和JSTL标签底层都是通过Java的ResourceBundle类来获取资源并设置参数的。如果弄java不知道这个ResourceBundle类就菜鸟了,比如搞个配置文件还写个FileReader在那搞,折腾半天,最后还不能把配置文件和jar包打在一起发布....例子,读取message_en.properties,里面内容myKey = hello, world.

复制代码
1privatestaticStringmyName;
2static{
3try{
4ResourceBundlebundle=ResourceBundle
5.getBundle("messages",Locale.ENGLISH);
6myName=bundle.getString("myKey").trim();
7}
8catch(Exceptionex){
9System.err.println("[Property]:Can'tLoadproperty.properties");
10myName="defaultname";
11
12System.out.println("myNamewillusethedefaultvalue:"+myName);
13
14}
复制代码

15}

ResourceBundle类有一点注意,给的key注意路径:比如你的文件clasPath路径是/temp/messages_cn.properties ,那么这个key应该是“temp.messages”。

有关ResourceBundle类的更多用法,参考这个网页。

Servlet和Spring访问资源文件

JSP和JSTL标签底层都是通过Java的ResourceBundle类来获取资源并设置参数的,而对于java web程序中Servlet访问资源文件可以通过ServletContext类中getResourceAsStream方法,它是通过Servlet容器来获得资源文件的,它使得Servlet程序可以访问web应用程序内部的任意位置的文件。(非Servlet中用classLoader,jdk中ClassLoader类专门提供了getResource等方法去装载资源文件,他们使用与查找Java类文件同样的方式去查找原文件,即在类 装载器所搜索的目录中查找。为了防止外部使用浏览器访问到资源文件,web应用程序中的资源文件通常应放到Web-INF目录或其子目录中。由于web应 用程序的类装载器会搜索web-inf/classes目录,所有ClassLoader.getResourceAsStream方法也可以访问该目录中的资源文件,但是,该方法不能访问web应用程序内的其他目录中的资源。)

复制代码
1InputStreamin=this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
2
3java.util.Propertiesproperties=newjava.util.Properties();
4properties.load(in);//得到的是map集合
5
6Stringurl=properties.getProperty("url");
7Stringusername=properties.getProperty("username");
复制代码

8Stringpassword=properties.getProperty("password");

Servlet访问资源文件要注意相对路径、绝对路径,以及权限问题,具体查看这个页面。

而Spring中的org.springframework.core.io.Resource接口代表着物理存在的任何资源,其继承于org.springframework.core.io.InputStreamSource;其子类有如下几 种:ByteArrayResource, ClassPathResource, DescriptiveResource, FileSystemResource, InputStreamResource, PortletContextResource,ServletContextResource, UrlResource 。常见的有下面四种:

  1. ClassPathResource:通过 ClassPathResource 以类路径的方式进行访问;
  2. FileSystemResource:通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
  3. ServletContextResource:通过ServletContextResource以相对于Web应用根目录的方式进行访问。例如:Resource resource = new ServletContextResource(servletContext, "/path/to/file");File resourceFile = resource.getFile();
  4. UrlResource :通过java.net.URL来访问资源,当然它也支持File格式,如“file:”

Servlet和多语言

HttpServletRequest支持一些接口来获得请求客户端浏览器的地区、语言和国家(IE-Internet Options设置-General-Language可以设置你的浏览器语言),然后HttpServletResponse通过设置http头的"Content-Language"来动态设置客户端语言。

复制代码
1importjava.io.*;
2importjavax.servlet.*;
3importjavax.servlet.http.*;
4importjava.util.Locale;
5
6publicclassDisplaySpanishextendsHttpServlet{
7
8publicvoiddoGet(HttpServletRequestrequest,
9HttpServletResponseresponse)
10throwsServletException,IOException
11{
12//Gettheclient'sLocale
13Localelocale=request.getLocale();
14Stringlanguage=locale.getLanguage();
15Stringcountry=locale.getCountry();
16
17//Setresponsecontenttype
18response.setContentType("text/html");
19PrintWriterout=response.getWriter();
20//Setspanishlanguagecode.
21response.setHeader("Content-Language","es");
22
23Stringtitle="EnEspañol";
24StringdocType=
25"<!doctypehtmlpublic\"-//w3c//dtdhtml4.0"+
26"transitional//en\">\n";
27out.println(docType+
28"<html>\n"+
29"<head><title>"+title+"</title></head>\n"+
30"<bodybgcolor=\"#f0f0f0\">\n"+
31"<h1>"+"EnEspa&ntilde;ol:"+"</h1>\n"+
32"<h1>"+"&iexcl;HolaMundo!"+"</h1>\n"+
33"</body></html>");
34}
复制代码

35}

Spring MVC+Freemarker+jQuery/js的多语言实现

上面说了那么多废话,现在进入正题Spring MVC+Freemarker+jQuery/js的多语言实现,最终我们要实现的是:

  1. 根据客户端浏览器语言显示相应的语言
  2. 用户可以动态切换语言,保存在Cookie中,下次自动使用该语言
  3. 静态html、jsp页面多语言、controller里面能获得多语言、freemarker多语言、jquery/js的多语言

首先说一下Spring MVC对多语言的支持可以看Spring官方网页,但我们用了Freemarker,这些有些麻烦。另外,Spring MVC提供了下面几种方式来支持多语言:

  1. 用param的方式:url?lang=de,就是URL的方式,然后用拦截器LocaleChangeInterceptor:来实现动态多语言。本文没有采用这种方式,不喜欢改变URL,一切应该是在背后默默进行的。
  2. 用Session方式来存储用户动态选择的语言:session过期就没有了,所以本文没有采用这种方式。
  3. 用Cookie的方式来存储用户动态选择的语言:本文采用这种方式,session过期了下次登录还是能记住,但同一机器多个用户需要区分。

具体实现:

1. 在Spring-servlet.xml(具体看自己项目中的命名)加入:

复制代码
1<beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
2<propertyname="basenames">
3<list>
4<value>resources/messages</value>
5</list>
6</property>
复制代码

7</bean>

2. 添加资源文件messages.properties, messages_en_US.properties, messages_zh_CN.properties,注意路径和上面配置的一致,在classpath的resources目录下:

3. 针对Freemarker的,首先Spring jar包反解出Spring.ftl,然后拷贝到你的ftl目录。这样比较变态,但这样就能在ftl文件中使用宏来获得需要的message了。

4.在Spring-servlet.xml(具体看自己项目中的命名)加入设置:Freemarker自动导入Spring.ftl宏。不用在每个ftl里面定义这个宏。

复制代码
1<beanid="freemarkerConfigurer"
2class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
3<propertyname="freemarkerSettings">
4<props>
5<propkey="auto_import">localization/spring.ftlasspring</prop>
6</props>
7</property>
复制代码

8</bean>

如下图:

5. 在freemarker中使用:<@spring.message "label.menu"/>

6. 如果不能自动获取宏,需要ftl中加入:<#import "/WEB-INF/views/localization/spring.ftl" as spring/>

7. 在Spring-servlet.xml(具体看自己项目中的命名)加入设置:

复制代码
1<beanid="localeResolver"class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
2<propertyname="cookieName"value="clientlanguage"/>
3<propertyname="cookieMaxAge"value="94608000"/>
4<propertyname="defaultLocale"value="en"/>
复制代码

5</bean>

8. 界面上加个按钮动态切换语言:

<span><ahref="javascript:void(0)"onclick="changeLanguage('en')">EN</a></span>
|

<span><ahref="javascript:void(0)"onclick="changeLanguage('fr')">FR</a></span>

9. 对于的动态切换语言的js:

复制代码
1functionchangeLanguage(language)
2{
3$.ajax({
4type:"POST",
5url:base+"ajax/changelanguage.do",
6data:"new_lang="+language,
7dataType:"json",
8async:true,
9error:function(data,error){alert("changelangerror!");},
10success:function(data)
11{
12window.location.reload();
13}
14});
复制代码

15}

10.Spring MVC后台对于的controller函数实现动态切换语言:(Spring会自动保存到上面配置的cookie。)

复制代码
1@RequestMapping(value="ajax/changelanguage.do",method=RequestMethod.POST)
2publicModelAndViewchangeLanguage(@RequestParamStringnew_lang,HttpServletResponseresponse)
3{
4Stringmsg="";
5
6try
7{
8LocaleResolverlocaleResolver=RequestContextUtils.getLocaleResolver(this.getRequest());
9if(localeResolver==null){
10thrownewIllegalStateException("NoLocaleResolverfound:notinaDispatcherServletrequest?");
11}
12
13LocaleEditorlocaleEditor=newLocaleEditor();
14localeEditor.setAsText(new_lang);
15localeResolver.setLocale(getRequest(),response,(Locale)localeEditor.getValue());
16
17msg="ChangeLanguageSuccess!";
18}
19catch(Exceptionex)
20{
21msg="error";
22}
23returnnewModelAndView("jsonView","json",msg);
复制代码

24}

11. 在其他controller里面如何获取当前语言并根据语言获取相应的文字? 首先在基类 baseController中加入:

@Autowired

protectedMessageSourcemessageSource;

然后在继承的controller里面加入参数:Locale locale,如下图:

然后就可以用messageSource 自动根据当前语言获取文字:messageSource.getMessage("myKey", null, locale)

12. 这里说一下,freemarker可能会报错:Template Spring.ftl not found!但事实上你的Spring.ftl是存在的,为何freemarer会找不到。这是因为freemarker寻找模版是根据配置的位置,templateLoaderPath,所以你配置的Spring.ftl路径必须是相对templateLoaderPath的相对路径。比如:


13. Javascript/jQuery/js的多语言问题:界面输入的validation往往会用js实现,而独立的js文件里面输出的validation message自然也要多语言。这里js的多语言问题有两种实现方法:1. 从后台读取资源,然后存入js数组,而且后台读取是异步的,这个会有性能问题。有兴趣的朋友可以去实现以下,有一些插件可以实现js读取后台i18n的java资源:参考1(jQuery i18n plugin),参考2(i18next),参考3(jawr).2. 在jsvalidation message放入单独的多个js文件,比如:validation_message.js和validation_message_fr_FR.js。本文采用的第二种方法。这种方法性能好,清晰,简单,因为validation messages可以拆开,而FCKEditor也是用这个方法。

首先增加validation.strings.js和validation.strings.fr.js(一个英语,一个发育),内容:

varmessageStrings={
my_key1:"hello",
my_key2:"world"

};

在js中可以这样用:messageStrings.my_key1.

然后是关键一步:根据cookie的语言,动态加载相应的js文件:

为了性能考虑,在页面最后加载,就是</body> 的前面,加入以下的js:

复制代码
<scripttype="text/javascript">
varbase="${base}/";//freemarkeruse
varlang=getCookie("clientlanguage");
varscript=document.createElement('script');
script.setAttribute("type","text/javascript");
if(lang==null){
script.setAttribute("src",base+"/resources/js/validation.strings.js");
}else{
script.setAttribute("src",base+"/resources/js/validation.strings."+lang+".js");
}
functiongetCookie(name){
vararr=document.cookie.match(newRegExp("(^|)"+name+"=([^;]*)(;|$)"));
if(arr!=null){returnunescape(arr[2]);}else{returnnull;}
}
复制代码

</script> (:上面少了一行:document.body.appendChild(script);)

如果语言有参数例如:mykey = please input {0},可以写个js函数来设置:

复制代码
/*
*varstr0="{0}mustsmallerthan{1}"
*varstr1=str0.fillArgs("apple","watermelon");
*srt1equalsto"applemustsmallerthanwatermelon"
*/
String.prototype.fillArgs=function()
{
varformated=this;
for(vari=0;i<arguments.length;i++)
{
varparam="\{"+i+"\}";
formated=formated.replace(param,arguments[i])
}
returnformated;
复制代码

}

jFreeReport的多语言国际化

jFreeReport通常和jFreeChart搭配使用并可以生成pdf,csv,xls,rtf,html,plain text....jFreeReport本身是支持本地化的。很简单,只要在base-report.xml里面配置一下ResourceBundle:

复制代码
<configuration>
<propertyname="org.jfree.report.modules.gui.csv.Enable">false</property>
<propertyname="org.jfree.report.modules.gui.html.Enable">false</property>
<propertyname="org.jfree.report.modules.gui.xls.Enable">false</property>
<propertyname="org.jfree.report.modules.gui.rtf.Enable">false</property>
<propertyname="org.jfree.report.modules.gui.plaintext.Enable">false</property>
<propertyname="org.jfree.report.ResourceBundle">temp.messages</property>
</configuration>
复制代码

ResourceBundle类有一点注意,给的key注意路径:比如你的文件clasPath路径是/temp/messages_cn.properties ,那么这个key应该是“temp.messages”。

然后在其它的各个report的xml里面进行如下配置获取键值:

<resource-labelx="0"y="10"width="100%"height="10"align="left">my.report.label123</resource-label>

在reportconfig.xml里面配置了ResourceBundle固然很好,但是如何把用户当前的语言传给jFreeReport呢?这个就需要自定义ResourceBundleFactory。先写一个ResourceBundleFactory类 :

复制代码
classbundleFactoryimplementsResourceBundleFactory
{
Localelocale;
publicbundleFactory(Localelocale)
{
this.locale=locale;
}

@Override
publicResourceBundlegetResourceBundle(Stringkey){
returnResourceBundle.getBundle(key,locale);
}

@Override
publicLocalegetLocale(){
returnlocale;
}
}
复制代码

这个ResourceBundleFactory类可以根据传进去的Locale来获取语言资源,locale从httpRequest可以获取。最后,在jFreeReport中调用这个ResourceBundleFactory:

复制代码
JFreeReportreport=generator.parseReport("/myreportconfigration.xml"));
report.setResourceBundleFactory(newbundleFactory(locale/*getfromhttp_request*/));
report.setProperty("titleString2",messageSource.getMessage("Reports.History.Pdf.title2",null,locale));
复制代码

上面那个设置属性 titleString是因为reportConfig.xml 里面有用到:

<string-fieldx="0"y="12"width="100%"height="10"fsbold="false"fontsize="8"vertical-alignment="middle"alignment="left"fieldname="titleString2"/>

总之,jFreeReport的国际化/本地化/多语言实现还是比较繁琐的,但总体还是支持的不错。

jqGrid的多语言/国际化/i18n实现

有时候会显示"No records to view",或者"Page 1 of 5",这些文字是需要国际化的。还好jqGrid支持他们。只要动态引用jqGrid/js/i18n/grid.locale-en.js,或者jqGrid/js/i18n/grid.locale-fr.js。具体动态引用的js:

复制代码
<scripttype="text/javascript">
varbase="/";
functiongetCookie(name){
vararr=document.cookie.match(newRegExp("(^|)"+name+"=([^;]*)(;|$)"));
if(arr!=null){returnunescape(arr[2]);}else{returnnull;}
}
varcurlang=getCookie("clientlanguage");
varscript=document.createElement('script');
script.setAttribute("type","text/javascript");
if(curlang==null||curlang=="en"){
script.setAttribute("src",base+"resources/js/jqGrid/js/i18n/grid.locale-en.js");
}else{
script.setAttribute("src",base+"resources/js/jqGrid/js/i18n/grid.locale-"+curlang+".js");
}
document.getElementsByTagName('head')[0].appendChild(script);
</script>
复制代码

把这段js放到html的head部分,就是动态根据当前的cookie设置的语言来加载响应的js,会在</head>前面动态引用js,注意是document.head.appendChild (document.getElementsByTagName('head')[0])哦,不是document.body.appendChild。 效果:

注意:动态加载和动态切换jqGrid的语言用上面的代码会出现各个浏览器的兼容性问题,原因是jqGrid/js/i18n/grid.locale-xx.js必须在引用jgGrid之前引用,而动态引用js的执行在各个浏览器(IE、Chrome、Firefox、Opera、Safari)里面顺序不一样,有的是立即同步执行,有的是异步执行,导致jqGrid使用的时候报异常。当然你可以用下面的带OnLoadComple callback的方法来强制同步动态加载引用外部js,保证它们是顺序加载引用和执行的:

复制代码
functionloadScript(head,url,callback){

varscript=document.createElement("script")
script.type="text/javascript";

if(script.readyState){//IE
script.onreadystatechange=function(){
if(script.readyState=="loaded"||
script.readyState=="complete"){
script.onreadystatechange=null;
callback();
}
};
}else{//Others
script.onload=function(){
callback();
};
}

script.src=url;
if(head)document.getElementsByTagName("head")[0].appendChild(script);
elsedocument.body.appendChild(script);
}
复制代码

但这样也会出现其他的问题,比如你在局部的ftl/html里面有内嵌的js:$("#abc").jqGrid.....这些是立即执行的,而上面的动态加载引用的js可能还没有加载完毕....这样的问题在各个浏览器兼容上面有问题。最终实现jqGrid多语言/国际化/本地化/i18n并能实时动态切换语言的解决方案是扩展jqgrid,具体看这个老外的帖子,demo在这儿,需要改造grid.locale-XX.js,注意不是引用的官方的jqGrid

jQuery.UI.DatePicker的多语言/国际化/i18n实现

jQuery.UI有一个DatePicker控件,也是需要多语言和国际化的。因为上面的文字比如月份:

首先去官网下载语言对应的datePicker文件,例如:jquery.ui.datepicker-fr.js就是法语的。然后在html的body后面动态加载响应的js即可,把下面的js调用一下,放在</body>前面就行了,会在</body>前面动态引用js。

复制代码
<scripttype="text/javascript">
functionhandleDatepickerI18n(){
varbase="/";
varlang=getCookie("clientlanguage");
if(lang==null||lang=="en")return;
varscript=document.createElement('script');
script.setAttribute("type","text/javascript");
script.setAttribute("src",base+"resources/js/UI/i18n/jquery.ui.datepicker-"+lang+".js");
document.body.appendChild(script);
}
</script>
复制代码

Spring mvc的主题Theme实现

Spring MVC对Theme主题的支持可以参考这个Spring官方网页,同上面的多语言类似,Spring MVC也提供了多种方式,比如url的param和拦截器、session和cookie等,这里我们还是用cookie的方式来实现。

1.在Spring-servlet.xml(具体看自己项目中的命名)加入设置:

复制代码
1<!--Theme-->
2<beanid="themeSource"
3class="org.springframework.ui.context.support.ResourceBundleThemeSource">
4<propertyname="basenamePrefix"value="resources/theme-"/>
5</bean>
6
7<beanid="themeResolver"class="org.springframework.web.servlet.theme.CookieThemeResolver">
8<propertyname="cookieName"value="clienttheme"/>
9<propertyname="cookieMaxAge"value="94608000"/>
10<propertyname="defaultThemeName"value="default"/>
复制代码
11</bean>

2. 在src/resources 添加两个文件: theme-default.properties, theme-blue.properties

theme-default.properties内容: css=themes/default.css

theme-blue.properties内容: css=themes/blue.css

3. 添加themes目录,添加两个文件:default.css, blue.css

default.css内容:

body {
background-color: white;
color: black;
}
blue.css内容:
body {
background-color: #DBF5FF;
color: #007AAB;
}

4. 界面上加一个按钮动态切换主题:

<span><ahref="javascript:void(0)"onclick="changeTheme('default')">default</a></span>
|

<span><ahref="javascript:void(0)"onclick="changeTheme('blue')">blue</a></span>

5. 按钮对应的js:

复制代码
functionchangeTheme(theme)
{
$.ajax({
type:"POST",
url:base+"ajax/changetheme.do",
data:"new_theme="+theme,
dataType:"json",
async:true,
error:function(data,error){alert("changethemeerror!");},
success:function(data)
{
window.location.reload();
}
});
复制代码

}

6.Spring MVC对应的后台controller函数实现动态切换主题:

复制代码
@RequestMapping(value="ajax/changetheme.do",method=RequestMethod.POST)
publicModelAndViewumChangeTheme(@RequestParamStringnew_theme,HttpServletResponseresponse)
{
Stringmsg="";

try
{ThemeResolverthemeResolver=RequestContextUtils.getThemeResolver(this.getRequest());
if(themeResolver==null){
thrownewIllegalStateException("NothemeResolverfound:notinaDispatcherServletrequest?");
}

themeResolver.setThemeName(getRequest(),response,new_theme);
msg="changeThemeSuccess!";
}
catch(Exceptionex)
{
msg="error";
}
returnnewModelAndView("jsonView","json",msg);
复制代码

}

7. 在页面中根据cookie动态加载主题相应的css(注意放在html开头来动态加载css) :

复制代码
<scripttype="text/javascript">
varbase="${base}/";//freemarkeruse

loadTheme();

functionloadTheme(){
vartheme=getCookie("clienttheme");
varhead=document.getElementsByTagName('HEAD').item(0);
varstyle=document.createElement('link');
style.rel='stylesheet';
style.type='text/css';
if(theme==null){
style.href=base+"/themes/default.css";
}else{
style.href=base+"/themes/"+theme+".css";
}
head.appendChild(style);
}

functiongetCookie(name){
vararr=document.cookie.match(newRegExp("(^|)"+name+"=([^;]*)(;|$)"));
if(arr!=null){returnunescape(arr[2]);}else{returnnull;}
}
复制代码

</script>

8. 如果你项目中用到其它jQuery插件,比如jQuery UI,比如jqGrid,要注意配合jqGrid的主题来动态切换。首先从http://jqueryui.com/themeroller/下载需要的jqGrid皮肤(你也可以创建自己的Theme这个jqGrid也支持的,事实上jqGrid用的是jQuery UI的ThemeRoller),然后在html中饮用相应的css即可(参考)。或者用js实现动态加载css(参加文中的代码实现动态加载css)。

9. 除了动态加载css,还可以在html或ftl中写动态css,更加方便。注意一点,在Freemarker中不能用<spring:theme code="abc"这样的语法,要这样用:

复制代码
<#assignmaincss>
<@spring.theme"stylesheet_main"/>
</#assign>

<linkhref="${base}/${maincss}?v=31"rel="stylesheet"type="text/css"/>
复制代码

注意这个stylesheet_main是在theme_xx.properties定义的:stylesheet_main=resources/css/theme/default/main.css

如果你运行上面的代码报错:Expression spring is undefined on .....,那么就是因为你没有引用...spring.ftl,参考本文上面的多语言的部分如何import这个spring.ftl吧。

总结

本文讲述了java web的多语言国际化实现和主题(Theme)的实现,具体来说是Spring MVC+Freemarker+Javascript的多语言(国际化i18n/本地化)主题(Theme)实现。总结一下,不比纯粹的Java Servlet国际化,由于我们用到多个框架(Spring MVC,Freemarker,jQuery,jqGrid....),所以实现多语言起来难度加大,具体来说就是要整合Spring MVC的国际化和Freemarker,这个会遇到很多问题。而且多语言散布在html、jsp、freemarker/*.frl、controller/Spring MVC、和javascript/js中,所以我们需要的是一个整体解决方案,


分享到:
评论
2 楼 linfanne 2012-12-28  
  哭了, 有一个地方写错了, 跟了2个多小时代码才找到原因

<propertyname="basenamePrefix"value="resources/theme-"/> 变成

<property name="basenamePrefix" value="theme-" />
1 楼 linfanne 2012-12-27  
无数的鲜花,多语言暂时不考虑,多主题刚好用到,

我一般都不回帖,但是你写的这个太好了, 

相关推荐

Global site tag (gtag.js) - Google Analytics