欢迎来到春季国际化(i18n)教程. 任何具有世界各地用户的Web应用程序, 国际化(i18n)或 本地化(L10n)对于更好的用户交互非常重要。 大多数Web应用程序框架提供了基于用户本地设置定位应用程序的简单方法。 春季也遵循模式,并通过使用春季拦截器,本地解决方案和资源包用于不同本地提供广泛的国际化支持(i18n)。
春季国际化i18n
Let's create a simple Spring MVC project where we will use request parameter to get the user locale and based on that set the response page label values from locale specific resource bundles. Create a Spring MVC Project in the Spring Tool Suite to have the base code for our application. If you are not familiar with Spring Tool Suite or Spring MVC Projects, please read Spring MVC Example. Our final project with localization changes looks like below image. We will look into all the parts of the application one by one.
春季 i18n Maven 配置
我们的 Spring MVC pom.xml 看起来像下面。
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>com.journaldev</groupId>
6 <artifactId>spring</artifactId>
7 <name>Springi18nExample</name>
8 <packaging>war</packaging>
9 <version>1.0.0-BUILD-SNAPSHOT</version>
10 <properties>
11 <java-version>1.6</java-version>
12 <org.springframework-version>4.0.2.RELEASE</org.springframework-version>
13 <org.aspectj-version>1.7.4</org.aspectj-version>
14 <org.slf4j-version>1.7.5</org.slf4j-version>
15 </properties>
16 <dependencies>
17 <!-- Spring -->
18 <dependency>
19 <groupId>org.springframework</groupId>
20 <artifactId>spring-context</artifactId>
21 <version>${org.springframework-version}</version>
22 <exclusions>
23 <!-- Exclude Commons Logging in favor of SLF4j -->
24 <exclusion>
25 <groupId>commons-logging</groupId>
26 <artifactId>commons-logging</artifactId>
27 </exclusion>
28 </exclusions>
29 </dependency>
30 <dependency>
31 <groupId>org.springframework</groupId>
32 <artifactId>spring-webmvc</artifactId>
33 <version>${org.springframework-version}</version>
34 </dependency>
35
36 <!-- AspectJ -->
37 <dependency>
38 <groupId>org.aspectj</groupId>
39 <artifactId>aspectjrt</artifactId>
40 <version>${org.aspectj-version}</version>
41 </dependency>
42
43 <!-- Logging -->
44 <dependency>
45 <groupId>org.slf4j</groupId>
46 <artifactId>slf4j-api</artifactId>
47 <version>${org.slf4j-version}</version>
48 </dependency>
49 <dependency>
50 <groupId>org.slf4j</groupId>
51 <artifactId>jcl-over-slf4j</artifactId>
52 <version>${org.slf4j-version}</version>
53 <scope>runtime</scope>
54 </dependency>
55 <dependency>
56 <groupId>org.slf4j</groupId>
57 <artifactId>slf4j-log4j12</artifactId>
58 <version>${org.slf4j-version}</version>
59 <scope>runtime</scope>
60 </dependency>
61 <dependency>
62 <groupId>log4j</groupId>
63 <artifactId>log4j</artifactId>
64 <version>1.2.15</version>
65 <exclusions>
66 <exclusion>
67 <groupId>javax.mail</groupId>
68 <artifactId>mail</artifactId>
69 </exclusion>
70 <exclusion>
71 <groupId>javax.jms</groupId>
72 <artifactId>jms</artifactId>
73 </exclusion>
74 <exclusion>
75 <groupId>com.sun.jdmk</groupId>
76 <artifactId>jmxtools</artifactId>
77 </exclusion>
78 <exclusion>
79 <groupId>com.sun.jmx</groupId>
80 <artifactId>jmxri</artifactId>
81 </exclusion>
82 </exclusions>
83 <scope>runtime</scope>
84 </dependency>
85
86 <!-- @Inject -->
87 <dependency>
88 <groupId>javax.inject</groupId>
89 <artifactId>javax.inject</artifactId>
90 <version>1</version>
91 </dependency>
92
93 <!-- Servlet -->
94 <dependency>
95 <groupId>javax.servlet</groupId>
96 <artifactId>servlet-api</artifactId>
97 <version>2.5</version>
98 <scope>provided</scope>
99 </dependency>
100 <dependency>
101 <groupId>javax.servlet.jsp</groupId>
102 <artifactId>jsp-api</artifactId>
103 <version>2.1</version>
104 <scope>provided</scope>
105 </dependency>
106 <dependency>
107 <groupId>javax.servlet</groupId>
108 <artifactId>jstl</artifactId>
109 <version>1.2</version>
110 </dependency>
111
112 <!-- Test -->
113 <dependency>
114 <groupId>junit</groupId>
115 <artifactId>junit</artifactId>
116 <version>4.7</version>
117 <scope>test</scope>
118 </dependency>
119 </dependencies>
120 <build>
121 <plugins>
122 <plugin>
123 <artifactId>maven-eclipse-plugin</artifactId>
124 <version>2.9</version>
125 <configuration>
126 <additionalProjectnatures>
127 <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
128 </additionalProjectnatures>
129 <additionalBuildcommands>
130 <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
131 </additionalBuildcommands>
132 <downloadSources>true</downloadSources>
133 <downloadJavadocs>true</downloadJavadocs>
134 </configuration>
135 </plugin>
136 <plugin>
137 <groupId>org.apache.maven.plugins</groupId>
138 <artifactId>maven-compiler-plugin</artifactId>
139 <version>2.5.1</version>
140 <configuration>
141 <source>1.6</source>
142 <target>1.6</target>
143 <compilerArgument>-Xlint:all</compilerArgument>
144 <showWarnings>true</showWarnings>
145 <showDeprecation>true</showDeprecation>
146 </configuration>
147 </plugin>
148 <plugin>
149 <groupId>org.codehaus.mojo</groupId>
150 <artifactId>exec-maven-plugin</artifactId>
151 <version>1.2.1</version>
152 <configuration>
153 <mainClass>org.test.int1.Main</mainClass>
154 </configuration>
155 </plugin>
156 </plugins>
157 </build>
158</project>
大部分代码是由STS自动生成的,除非我更新了春季版本,以使用最新版本为 4.0.2.RELEASE。
春季资源包
为了简化,假设我们的应用程序仅支持两个本地 - en和 fr. 如果没有指定用户本地,我们将使用英语作为默认本地。
1label.title=Login Page
2label.firstName=First Name
3label.lastName=Last Name
4label.submit=Login
messages_fr.properties 代码:
1label.title=Connectez-vous page
2label.firstName=Pr\u00E9nom
3label.lastName=Nom
4label.submit=Connexion
请注意,我在法语局部资源包中使用特殊字符的独代码,以便在向客户端请求发送的HTML响应中得到正确的解释. 另一个重要点要注意的是,两个资源包都在应用程序的类路径中,他们的名称有messages_{locale}.properties
的格式。
春季i18n控制器类别
我们的控制器类非常简单,它只会登录用户本地并返回 home.jsp 页面作为响应。
1package com.journaldev.spring;
2
3import java.util.Locale;
4
5import org.slf4j.Logger;
6import org.slf4j.LoggerFactory;
7import org.springframework.stereotype.Controller;
8import org.springframework.ui.Model;
9import org.springframework.web.bind.annotation.RequestMapping;
10import org.springframework.web.bind.annotation.RequestMethod;
11
12/**
13 * Handles requests for the application home page.
14 */
15@Controller
16public class HomeController {
17
18 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
19
20 /**
21 * Simply selects the home view to render by returning its name.
22 */
23 @RequestMapping(value = "/", method = RequestMethod.GET)
24 public String home(Locale locale, Model model) {
25 logger.info("Welcome home! The client locale is {}.", locale);
26
27 return "home";
28 }
29
30}
春季 i18n JSP 页面
我们的 home.jsp 页面代码如下。
1<%@taglib uri="https://www.springframework.org/tags" prefix="spring"%>
2<%@ page session="false"%>
3<html>
4<head>
5<title><spring:message code="label.title" /></title>
6</head>
7<body>
8 <form method="post" action="login">
9 <table>
10 <tr>
11 <td><label> <strong><spring:message
12 code="label.firstName" /></strong>
13 </label></td>
14 <td><input name="firstName" /></td>
15 </tr>
16 <tr>
17 <td><label> <strong><spring:message
18 code="label.lastName" /></strong>
19 </label></td>
20 <td><input name="lastName" /></td>
21 </tr>
22 <tr>
23 <spring:message code="label.submit" var="labelSubmit"></spring:message>
24 <td colspan="2"><input type="submit" value="${labelSubmit}" /></td>
25 </tr>
26 </table>
27 </form>
28</body>
29</html>
唯一值得提到的部分是使用 spring:message来检索该代码的消息. 确保 Spring 标签库是使用 [taglib jsp 指令](/community/tutorials/jsp-directives-page-include-taglib-example `JSP 指令 – 页面,包括和 taglib 示例)配置的。
春季国际化 i18n - Bean 配置文件
春豆配置文件是所有魔法发生的地方,这是春豆框架的美丽,因为它有助于我们更多地关注商业逻辑,而不是编码微不足道的任务。
1<?xml version="1.0" encoding="UTF-8"?>
2<beans:beans xmlns="https://www.springframework.org/schema/mvc"
3 xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
4 xmlns:context="https://www.springframework.org/schema/context"
5 xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
6 https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
7 https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
8
9 <!-- DispatcherServlet Context: defines this servlet's request-processing
10 infrastructure -->
11
12 <!-- Enables the Spring MVC @Controller programming model -->
13 <annotation-driven />
14
15 <!-- Handles HTTP GET requests for /resources/** by efficiently serving
16 up static resources in the ${webappRoot}/resources directory -->
17 <resources mapping="/resources/**" location="/resources/" />
18
19 <!-- Resolves views selected for rendering by @Controllers to .jsp resources
20 in the /WEB-INF/views directory -->
21 <beans:bean
22 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
23 <beans:property name="prefix" value="/WEB-INF/views/" />
24 <beans:property name="suffix" value=".jsp" />
25 </beans:bean>
26
27 <beans:bean id="messageSource"
28 class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
29 <beans:property name="basename" value="classpath:messages" />
30 <beans:property name="defaultEncoding" value="UTF-8" />
31 </beans:bean>
32
33 <beans:bean id="localeResolver"
34 class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
35 <beans:property name="defaultLocale" value="en" />
36 <beans:property name="cookieName" value="myAppLocaleCookie"></beans:property>
37 <beans:property name="cookieMaxAge" value="3600"></beans:property>
38 </beans:bean>
39
40 <interceptors>
41 <beans:bean
42 class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
43 <beans:property name="paramName" value="locale" />
44 </beans:bean>
45 </interceptors>
46
47 <context:component-scan base-package="com.journaldev.spring" />
48
49</beans:beans>
- 注释驱动的标签使Captain编程模式成为了Captain编程模式,没有它Spring将不承认我们的Home Captain是客户请求的处理者.
- context: 组件-扫描 提供了Spring查找注释组件并自动注册为Spring Bean的软件包.
- i18n 用于我们的应用。 ** 基名** 属性用于提供资源包的位置。
classath:messages' 是指资源捆绑位于类路口,并遵循
messages__locale}.propertys`的名称模式。默认编码属性用于定义用于信件的编码。 - ** locale Resolver ** bean of type " org.springframework.web. servlet.i18n.Cookie LocaleResolver" 用于在客户端请求中设置一个饼干,以便进一步请求可以方便地识别用户本地化。 例如,我们可以要求用户在首次启动网络应用程序时选择该地块,并使用cookie,我们可以识别用户地块并自动发送地块特定响应. 我们还可以指定饼干在被客户端浏览器过期并删除前的默认用地,饼干名称和最大年龄. 如果您的应用程序维持用户会话, 您也可以在用户会话中使用
org. springframework.web. servlet. i18n. Session LocaleResolver
来使用 locale 属性 。 该配置类似于 Cookie LocaleResolver. QQ <bean id="localeResolver" class=".org.springframework.web.servlet.i18n.sessionlocaleResolver" <财产名称="默认本地语"值="en"/ (如果我们不注册任何"本地语解",Acceptheader LocaleResolver将默认使用,它通过检查客户端HTTP请求中的"接受语解析"头. - org.springframework.web. servlet.i18n.locoleChangeInterceptor"截取器被配置为截取用户请求并识别用户端. 参数名称是可配置的,我们正在对地语使用请求参数名称作为"locale". 没有这个截取器,我们就无法改变用户的地块,并根据用户的新地块设置发送响应. 它需要成为受器元素的一部分,否则斯普林不会将其配置为截取器. ( (英语)
如果您想知道告诉 Spring 框架下载我们的语境配置的配置,它就在我们的 MVC 应用程序的部署描述器中。
1<servlet>
2 <servlet-name>appServlet</servlet-name>
3 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
4 <init-param>
5 <param-name>contextConfigLocation</param-name>
6 <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
7 </init-param>
8 <load-on-startup>1</load-on-startup>
9</servlet>
10
11<servlet-mapping>
12 <servlet-name>appServlet</servlet-name>
13 <url-pattern>/</url-pattern>
14</servlet-mapping>
We can change the location or name of the context file by changing the web.xml configuration. Our Spring i18n application is ready, just deploy it in any servlet container. Usually I export it as WAR file in a standalone tomcat web server webapps directory. Here are the screenshots of our application home page with different locales. Default Home Page (en locale): Passing Locale as parameter (fr locale):
Further requests without locale:
As you can see in the above image that we are not passing locale information in the client request but still our application identifies the user locale. You must have guessed by now that it's because of the CookieLocaleResolver bean that we configured in our spring bean configuration file. However you can check your browser cookies data to confirm it. I am using chrome and below image shows the cookie data stored by the application.
Notice that cookie expiry time is one hour i.e 3600 seconds as configured by cookieMaxAge property. If you will check server logs, you can see that locale is getting logged.
1INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en.
2INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is fr.
3INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is fr.
这是春季i18n示例应用程序的全部,从下面的链接下载示例项目,并玩它来了解更多。