博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring MVC+Freemarker+Javascript的多语言(国际化i18n/本地化)和主题(Theme)实现
阅读量:5795 次
发布时间:2019-06-18

本文共 17684 字,大约阅读时间需要 58 分钟。

导语 

本文说说java web的多语言国际化实现和主题(Theme)的实现,具体到框架是++/JS的多语言国际化实现和主题(Theme)的实现。如果一个系统会被多个国家使用,则多语言国际化/本地化是必须的。其实多语言只是的一部分,国际化(i18n)/本地化(l10n)(Wiki:)还包括货币、时区、符号、格式等其它内容。每种语言基本都支持国际化,比如.NET, php都支持,当然java也一样。Java是一种基于Unicode的编程语言,提供了资源绑定()、地区()、时区()等支持国际化。本文只说多语言(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里面的资源必须经过编码,不允许里面出现法文、德文、中文、日文等字符,而必须是字符。转可以使用JSK自带的工具,位于JDK安装目录的bin目录下,双击运行,输入中午或日文或法文,格式:native2ascii -[options] [inputfile [outputfile]],例如:native2ascii -encoding UTF-8 c:\message_de_DE.txt c:\message_de_DE.properties,回车开始转换。

ResourceBundle类

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

 1 
private 
static String myName;
 2 
static {
 3  
try {
 4    ResourceBundle bundle = ResourceBundle
 5      .getBundle("messages", Locale.ENGLISH);
 6    myName = bundle.getString("myKey").trim();
 7  }
 8  
catch(Exception ex) {
 9    System.err.println(  "[Property]:Can't Load property.properties");
10    myName = "default name";
11    
12    System.out.println(  "myName will use the default value: " + myName);
13   
14  }

15 } 

 

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

 

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

Servlet和Spring访问资源文件

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

1 InputStream in=
this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
2 
3   java.util.Properties properties=
new java.util.Properties();
4   properties.load(in); 
//
得到的是map集合
5   
6   String url=properties.getProperty("url");
7   String username=properties.getProperty("username");

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

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

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

  1. ClassPathResource:通过 ClassPathResource 以类路径的方式进行访问;
  2. FileSystemResource:通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
  3. :通过 以相对于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通过设置的""来动态设置客户端语言。

 1 
import java.io.*;
 2 
import javax.servlet.*;
 3 
import javax.servlet.http.*;
 4 
import java.util.Locale;
 5 
 6 
public 
class DisplaySpanish 
extends HttpServlet{
 7     
 8   
public 
void doGet(HttpServletRequest request,
 9                     HttpServletResponse response)
10             
throws ServletException, IOException
11   {
12     
//
Get the client's Locale
13     Locale locale = request.getLocale();
14     String language = locale.getLanguage();
15     String country = locale.getCountry();
16 
17     
//
 Set response content type
18     response.setContentType("text/html");
19     PrintWriter out = response.getWriter();
20     
//
 Set spanish language code.
21     response.setHeader("Content-Language", "es");
22 
23     String title = "En Español";
24     String docType =
25      "<!doctype html public \"-//w3c//dtd html 4.0 " +
26      "transitional//en\">\n";
27      out.println(docType +
28      "<html>\n" +
29      "<head><title>" + title + "</title></head>\n" +
30      "<body bgcolor=\"#f0f0f0\">\n" +
31      "<h1>" + "En Espa&ntilde;ol:" + "</h1>\n" +
32      "<h1>" + "&iexcl;Hola Mundo!" + "</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的多语言

 

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

 

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

 

具体实现:

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

1 
<
bean 
id
="messageSource"
 class
="org.springframework.context.support.ResourceBundleMessageSource"
>  
2   
<
property 
name
="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 
<
bean 
id
="freemarkerConfigurer"
2 
        class
="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
>
3     
<
property 
name
="freemarkerSettings"
>
4         
<
props
>
5             
<
prop 
key
="auto_import"
>localization/spring.ftl as spring
</
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 
<
bean 
id
="localeResolver"
 class
="org.springframework.web.servlet.i18n.CookieLocaleResolver"
>
2     
<
property 
name
="cookieName"
 value
="clientlanguage"
/>
3     
<
property 
name
="cookieMaxAge"
 value
="94608000"
/>
4     
<
property 
name
="defaultLocale"
 value
="en"
 
/>  

5 </bean>

 

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

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

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

 

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

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

15 }

 

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

 1 @RequestMapping(value = "ajax/changelanguage.do", method = RequestMethod.POST)
 2 
public ModelAndView changeLanguage(@RequestParam String new_lang, HttpServletResponse response)
 3 {
 4     String msg = "";
 5     
 6     
try
 7     {
 8         LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(
this.getRequest());  
 9         
if (localeResolver == 
null) {  
10             
throw 
new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");  
11         } 
12         
13         LocaleEditor localeEditor = 
new LocaleEditor();  
14         localeEditor.setAsText(new_lang);
15         localeResolver.setLocale(getRequest(), response, (Locale)localeEditor.getValue());  
16                                 
17         msg = "Change Language Success!";
18     }
19     
catch(Exception ex)
20     {
21         msg = "error";
22     }
23     
return 
new ModelAndView("jsonView", "json", msg);

24 }  

 

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

@Autowired

protected MessageSource messageSource;

然后在继承的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(),参考2(),参考3(). 2. 在js validation message放入单独的多个js文件,比如:validation_message.js和validation_message_fr_FR.js。本文采用的第二种方法。这种方法性能好,清晰,简单,因为validation messages可以拆开,而FCKEditor也是用这个方法。

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

var messageStrings = {
   my_key1: "hello",
   my_key2: "world"

};

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

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

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

<script type="text/javascript">
    
var base = "${base}/";
//
freemarker use
    
var lang = getCookie("clientlanguage");
    
var script=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");
    }
    
function getCookie(name){
      
var arr = document.cookie.match(
new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
      
if(arr != 
null) { 
return unescape(arr[2]);} 
else{  
return 
null; }
    }

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

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

    
/*
 
     * var str0 = "{0} must smaller than {1}" 
     * var str1 = str0.fillArgs("apple", "watermelon"); 
     * srt1 equals to "apple must smaller than watermelon" 
     
*/  
    String.prototype.fillArgs = 
function()  
    {  
        
var formated = 
this;  
        
for ( 
var i=0;i<arguments.length;i++)  
        {  
            
var param = "\{"+i+"\}";  
            formated = formated.replace(param,arguments[i])  
        }  
        
return formated;  

    }  

 

jFreeReport的多语言国际化

 

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

 

 

  
<
configuration
> 
    
<
property 
name
="org.jfree.report.modules.gui.csv.Enable"
>false
</
property
>
    
<
property 
name
="org.jfree.report.modules.gui.html.Enable"
>false
</
property
>
    
<
property 
name
="org.jfree.report.modules.gui.xls.Enable"
>false
</
property
>
    
<
property 
name
="org.jfree.report.modules.gui.rtf.Enable"
>false
</
property
>
    
<
property 
name
="org.jfree.report.modules.gui.plaintext.Enable"
>false
</
property
>
    
<
property 
name
="org.jfree.report.ResourceBundle"
>temp.messages
</
property
>      
  
</
configuration
>

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

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

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

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

class bundleFactory 
implements ResourceBundleFactory
{
    Locale locale;
    
public bundleFactory(Locale locale)
    {
        
this.locale=locale;
    }
    
    @Override
    
public ResourceBundle getResourceBundle(String key) {
        
return ResourceBundle.getBundle(key, locale);
    }
    
    @Override
    
public Locale getLocale() {
        
return locale;
    }
}

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

JFreeReport report = generator.parseReport("/myreportconfigration.xml"));
report.setResourceBundleFactory(
new bundleFactory(locale 
/*
get from http_request
*/));
report.setProperty("titleString2", messageSource.getMessage("Reports.History.Pdf.title2", 
null, locale));

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

<
string-field 
x
="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:

<script type="text/javascript">
var base = "/";
function getCookie(name){
    
var arr = document.cookie.match(
new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
    
if(arr != 
null) { 
return unescape(arr[2]);} 
else{  
return 
null; }
}
var curlang = getCookie("clientlanguage");
var script=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,保证它们是顺序加载引用和执行的:

function loadScript(head, url, callback){
    
var script = 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);
    
else document.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。

<script type="text/javascript">
  
function handleDatepickerI18n(){
       
var base="/";
      
var lang = getCookie("clientlanguage");
      
if(lang == 
null || lang == "en") 
return;
      
var script=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实现

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

 

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

 1 
<!--
 Theme 
-->
 2 
<
bean 
id
="themeSource"
 3 
    class
="org.springframework.ui.context.support.ResourceBundleThemeSource"
>
 4         
<
property 
name
="basenamePrefix"
 value
="resources/theme-"
 
/>
 5 
</
bean
>
 6 
 7 
<
bean 
id
="themeResolver"
 class
="org.springframework.web.servlet.theme.CookieThemeResolver"
>
 8     
<
property 
name
="cookieName"
 value
="clienttheme"
/>
 9     
<
property 
name
="cookieMaxAge"
 value
="94608000"
/>
10     
<
property 
name
="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
><
href
="javascript:void(0)"
 onclick
="changeTheme('default')"
>default
</
a
></
span
>
|

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

 

5. 按钮对应的js:

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

 

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

@RequestMapping(value = "ajax/changetheme.do", method = RequestMethod.POST)
 
public ModelAndView umChangeTheme(@RequestParam String new_theme, HttpServletResponse response)
 {
     String msg = "";
     
     
try
     {    ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(
this.getRequest());
         
if (themeResolver == 
null) {  
             
throw 
new IllegalStateException("No themeResolver found: not in a DispatcherServlet request?");  
         } 
         
         themeResolver.setThemeName(getRequest(), response, new_theme);
         msg = "change Theme Success!";
     }
     
catch(Exception ex)
     {
         msg = "error";
     }
     
return 
new ModelAndView("jsonView", "json", msg);

 }  

 

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

<script type="text/javascript">
    
var base = "${base}/";
//
freemarker use
    
    loadTheme();
    
     
function loadTheme(){ 
       
var theme = getCookie("clienttheme");
       
var head = document.getElementsByTagName('HEAD').item(0);
        
var style=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);
    }
        
    
function getCookie(name){
          
var arr = document.cookie.match(
new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
          
if(arr != 
null) { 
return unescape(arr[2]);} 
else{  
return 
null; }
     }

</script> 

 

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

 

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

<
#assign 
maincss
>
    
<
@spring
.theme "stylesheet_main"
/>
</
#assign
>
<
link 
href
="${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国际化,由于我们用到多个框架(, , , ....),所以实现多语言起来难度加大,具体来说就是要整合的国际化和,这个会遇到很多问题。而且多语言散布在html、jsp、freemarker/*.frl、controller/Spring MVC、和javascript/js中,所以我们需要的是一个整体解决方案,本文供有用到的朋友参考。如果使用上有问题,可以直接在下面留言。

 

转载地址:http://lnffx.baihongyu.com/

你可能感兴趣的文章
JavaWeb笔记——JSTL标签
查看>>
一些实用性的总结与纠正
查看>>
Kubernetes概念
查看>>
spring技术内幕读书笔记之IoC容器的学习
查看>>
自动生成四则运算题目
查看>>
Android学习系列(5)--App布局初探之简单模型
查看>>
git回退到某个历史版本
查看>>
HTML5基础(二)
查看>>
在Mac 系统下进行文件的显示和隐藏
查看>>
ue4(c++) 按钮中的文字居中的问题
查看>>
Hadoop日记Day1---Hadoop介绍
查看>>
Android学习笔记——文件路径(/mnt/sdcard/...)、Uri(content://media/external/...)学习
查看>>
Echart:前端很好的数据图表展现工具+demo
查看>>
Linux VNC黑屏(转)
查看>>
Java反射简介
查看>>
day8--socket网络编程进阶
查看>>
node mysql模块写入中文字符时的乱码问题
查看>>
分析Ajax爬取今日头条街拍美图
查看>>
内存分布简视图
查看>>
如何学习虚拟现实技术vr? vr初级入门教程开始
查看>>