欢迎使用springinternationalization(i18n)教程。任何用户遍布全球的网络应用程序,国际化(i18n)或本地化(L10n)对于更好的用户交互非常重要。
大多数web应用程序框架都提供了基于用户区域设置来本地化应用程序的简单方法。Spring也遵循这种模式,通过使用Spring拦截器、区域解析程序和针对不同地区的资源包,为国际化(i18n)提供了广泛的支持。
关于java中i18n的一些早期文章。
- Java国际化示例
- Struts2国际化示例
目录
Spring国际化i18n
让我们创建一个简单的Spring Mvc项目,在这个项目中,我们将使用request参数获取用户区域设置,并在此基础上设置来自特定于语言环境的资源包的响应页面标签值。
在Spring工具套件中创建一个Spring Mvc项目,以获得应用程序的基本代码。如果您不熟悉Spring工具套件或Spring Mvc项目,请阅读Spring MVC示例.
我们的最终项目本地化变化如下图。我们将逐一研究应用程序的所有部分。
springi18n Maven配置
我们的SpringMVCpom.xml文件如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>spring</artifactId>
<name>Springi18nExample</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</java-version>
<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
大部分代码都是由STS自动生成的,除了我已经更新了Spring版本以使用最新的版本作为4.0.2.RELEASE。我们可以删除依赖项或更新其他依赖项的版本,但为了简单起见,我保留了它们。
Spring资源包
为了简单起见,假设我们的应用程序只支持两个语言环境’;英语和法国. 如果没有指定用户区域设置,我们将使用英语作为默认区域设置。让我们为这两个将在JSP页面中使用的语言环境创建spring资源包。
消息_英语属性代码:
label.title=Login Page
label.firstName=First Name
label.lastName=Last Name
label.submit=Login
消息_fr.属性代码:
label.title=Connectez-vous page
label.firstName=Pru00E9nom
label.lastName=Nom
label.submit=Connexion
注意,我在法语语言环境资源包中对特殊字符使用unicode,以便在发送到客户机请求的HTML响应中正确地解释它。
另一个需要注意的重要点是,这两个资源包都位于应用程序的类路径中,它们的名称的模式为“;messages{locale}.properties”;。稍后我们将了解为什么这些很重要。
SpringI18N控制器类
我们的控制器类非常简单,它只记录用户区域设置并返回主页.jsp页面作为响应。
package com.journaldev.spring;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
return "home";
}
}
JSP i18n第18页
我们的主页.jsp页面代码如下所示。
<%@taglib uri="https://www.springframework.org/tags" prefix="spring"%>
<%@ page session="false"%>
<html>
<head>
<title><spring:message code="label.title" /></title>
</head>
<body>
<form method="post" action="login">
<table>
<tr>
<td><label> <strong><spring:message
code="label.firstName" /></strong>
</label></td>
<td><input name="firstName" /></td>
</tr>
<tr>
<td><label> <strong><spring:message
code="label.lastName" /></strong>
</label></td>
<td><input name="lastName" /></td>
</tr>
<tr>
<spring:message code="label.submit" var="labelSubmit"></spring:message>
<td colspan="2"><input type="submit" value="${labelSubmit}" /></td>
</tr>
</table>
</form>
</body>
</html>
唯一值得一提的是Spring:消息使用给定代码检索消息。确保Spring标记库是使用taglib jsp指令.Spring负责加载适当的资源包消息,并使其可供JSP页面使用。
springinternationalization i18n–;Bean配置文件
Spring Bean配置文件是所有神奇发生的地方。这就是Spring框架的优点,因为它帮助我们更加关注业务逻辑,而不是为琐碎的任务编写代码。让我们看看我们的Spring Bean配置文件是什么样子的,我们将看一下每一个bean。
servlet-上下文.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet"s request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
>
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="messageSource"
>
<beans:property name="basename" value="classpath:messages" />
<beans:property name="defaultEncoding" value="UTF-8" />
</beans:bean>
<beans:bean id="localeResolver"
>
<beans:property name="defaultLocale" value="en" />
<beans:property name="cookieName" value="myAppLocaleCookie"></beans:property>
<beans:property name="cookieMaxAge" value="3600"></beans:property>
</beans:bean>
<interceptors>
<beans:bean
>
<beans:property name="paramName" value="locale" />
</beans:bean>
</interceptors>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
- 注解驱动的tag支持控制器编程模型,没有它,Spring将不会将HomeController识别为客户端请求的处理程序。
- 上下文:组件扫描提供一个包,Spring将在其中查找带注解的组件并将其自动注册为Spring Bean。
- 消息源bean被配置为为为我们的应用程序启用i18n。基名属性用于提供资源包的位置。
classpath:messages
means that resource bundles are located in the classpath and follows name pattern asmessages_{locale}.properties
. defaultEncoding property is used to define the encoding used for the messages. - 局部求解器豆子类型
org.springframework.web.servlet.i18n.CookieLocaleResolver
is used to set a cookie in the client request so that further requests can easily recognize the user locale. For example, we can ask user to select the locale when he launches the web application for the first time and with the use of cookie, we can identify the user locale and automatically send locale specific response. We can also specify the default locale, cookie name and maximum age of the cookie before it gets expired and deleted by the client browser.如果应用程序维护用户会话,则还可以使用
org.springframework.web.servlet.i18n.SessionLocaleResolver
as localeResolver to use a locale attribute in the user’s session. The configuration is similar to CookieLocaleResolver.<bean id="localeResolver" > <property name="defaultLocale" value="en" /> </bean>
如果我们不注册任何本地解算器;,接受者头部局部清除器默认情况下将使用,它通过检查
accept-language
header in the client HTTP request. org.springframework.web.servlet.i18n.LocaleChangeInterceptor
interceptor is configured to intercept the user request and identify the user locale. The parameter name is configurable and we are using request parameter name for locale as “locale”. Without this interceptor, we won’t be able to change the user locale and send the response based on the new locale settings of the user. It needs to be part of 拦截器元素,否则Spring不会将其配置为拦截器。
如果您想知道告诉springframework加载上下文配置的配置,那么它存在于MVC应用程序的部署描述符中。
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
我们可以通过更改web.xml文件配置。
我们的springi18n应用程序已经准备好了,只需将其部署到任何servlet容器中即可。通常我将其作为WAR文件导出到一个独立的tomcatweb服务器webapps目录中。
以下是我们的应用程序主页的屏幕截图。
如上图所示,我们没有在客户端请求中传递区域设置信息,但我们的应用程序仍然标识用户区域设置。现在您一定已经猜到了,这是因为我们在Spring Bean配置文件中配置的CookieLocaleResolver bean。但是你可以检查你的浏览器cookies数据来确认它。我正在使用chrome,下面的图片显示了应用程序存储的cookie数据。
请注意,cookie过期时间为一小时,即3600秒,由cookieMaxAge属性配置。
如果您检查服务器日志,您可以看到语言环境正在被记录。
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en.
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is fr.
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is fr.
这就是springi18n示例应用程序的全部内容,请从下面的链接下载示例项目,并使用它来了解更多信息。