11.12.2012

Spring mvс и Internationalization (I18N).

Для работы I18N в нашем Spring mvс приложении нужно правильно сконфигурировать компоненты которые отвечают за работу с локалью и интернациональными сообщениями, так называемыми файлами BundleMessage.properties. Для этого нам нужно настроить интерфейс org.springframework.context.MessageSource который позволяет нам работать с I18N файлами в зависимости от установленой локали. Определить текущую локаль запроса нам помогает интерфейс org.springframework.web.servlet.LocaleResolver, а изменять org.springframework.web.servlet.i18n.LocaleChangeInterceptor. Все что нужно запомнить 1-й интерфейс отвечает за место где хранятся файлы ресурсов, 2-й где хранится локаль пользователя, 3-й отвечает за смену локали. Давайте расмотрим все по порядку.
Нам нужны 2 файла Application.properties c данными:
Button.text=Click me english
и Application_ru_RU.properties:
Button.text=Click me По русски!
в зависимости от локали мы будем использовать тот или иной файл для вывода сообщений. За пути где лежат файлы ответственнен класс ReloadableResourceBundleMessageSource который наследуется от интерфейса MessageSource:
<beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            /> 
обратите внимание на параметры p:basenames="WEB-INF/i18n/Application" - указывает путь где нужно искать наши porperties файлы, p:fileEncodings="UTF8" p:defaultEncoding="UTF8" указываем  что исходная кодировка наших porperties файлов UTF8. И так перейдем к следующему интерфейсу - LocaleResolver который ответственен за установку Locale отображаемой страницы, есть несколько класов которые реализуют этот интерфейс и соответсвенно их можно использовать в настройке Spring контекста web приложения, давайте расмотрим их - как они реализуют смену и установку Locale. Первый из них AcceptHeaderLocaleResolver - он берет свою Locale из заголовка HTTP Header Accept-Language, как мы знаем обычно этот заголовок устанавливается браузером клиента и изменить его программно нельзя, используется поумолчанию:
<beans:bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"
                id="localeResolver" />
Второй это CookieLocaleResolver использует для хранения Locale технологию Cookie, соответственно можно задать имя переменной Cookie, в нашем случае в p:cookieName="localeUser" будет храниться наша Locale и каждый пользователь может переустановить его на свое усмотрение.
<beans:bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
                id="localeResolver" p:cookieName="localeUser" p:defaultLocale="en_US"/>
Если в Cookie нет установленного localeUser параметра то берется по умолчанию default значение p:defaultLocale="en_US" иначе используется Locale из заголовка HTTP Header Accept-Language. Следующий FixedLocaleResolver устанавливает фиксированную Locale на все время жизни web приложения параметр p:defaultLocale="en_US", в дальнейшем параметр не может изменяться программно.
<beans:bean class="org.springframework.web.servlet.i18n.FixedLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
И последний SessionLocaleResolver хранит Locale в сессии программы (HttpSession)если нет сохраненного значения в сессии то берется по умолчанию default значение p:defaultLocale="en_US" а если не установлено p:defaultLocale то используется Locale из заголовка HTTP Header Accept-Language. Программно может меняться.
<beans:bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
И напоследок хочу упомянуть интерфейс который позволяет нам менять мокаль программно LocaleChangeInterceptor:
<interceptors>
        <beans:bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
                    p:paramName="lang"/>
    </interceptors>
что бы сменить локаль нам нужно только отослать переменную lang c нужной локалью например ru_RU на http://localhost:8080/phone/spring/?lang=ru_RU название переменной настраивается параметром p:paramName="lang".
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
 
 xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.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 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <beans:property name="prefix" value="/WEB-INF/views/" />
  <beans:property name="suffix" value=".jsp" />
        <beans:property name="contentType" value="text/html;charset=UTF-8"/>
 </beans:bean>
 
 <!-- Imports user-defined @Controller beans that process client requests -->
 <beans:import resource="controllers.xml" />

    <beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            />
    <!-- 1 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"
                id="localeResolver" />-->
    <!-- 2 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
                id="localeResolver" p:cookieName="localeUser" p:defaultLocale="en_US"/>
    -->
    <!-- 3 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.FixedLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>-->
    <!-- 4 -->
    <beans:bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
    <interceptors>
        <beans:bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
                    p:paramName="lang"/>
    </interceptors>
 
</beans:beans>
Если вы используете для отображения страницы jsp то вы должны использовать Spring Tag Library для работы с internationalization (I18N), для этого вам необходимо в начало страницы добавить <%@ taglib uri="http://www.springframework.org/tags" prefix="msg" %> в нашем случае мы создаем переменную и присваиваем ей значение Button.text выводим значение переменной ${text}
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="msg" %>
<%@ page session="false" %>
<html>
<head>
 <title>Home</title>
</head>
<body>
<h1> 
 Hello world!
</h1>
  <msg:message code="Button.text" var="test"/>
  ${test} <br/> ${pageContext.response.locale} <br/> ${controllerMessage}
</body>
</html>
и на последок обязательно нужно следить за локализацией всего web приложения от начала и до конца все файлы, все ресурсы, все запросы, в моем приложении по умолчанию используют кодировку UTF-8:
Первое все символы в запросе и ответе UTF-8
<!-- Creates the Spring Container shared by all Servlets and Filters -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Второе все файлы набраны в кодировке UTF-8. Третье в jsp файле установлены заголовки
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page pageEncoding="UTF-8" %>
...
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<head> 
в четвертых на правильную кодировку настроен contentType класса InternalResourceViewResolver
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/"/>
        <beans:property name="suffix" value=".jsp"/>
        <beans:property name="contentType" value="text/html;charset=UTF-8"/> 
</beans:bean>
в пятых правильно настроен p:fileEncodings и p:defaultEncoding класса ReloadableResourceBundleMessageSource
<beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            />
в шестых использую maven для компиляции приложения, у него настроена кодировка при сборке на UTF-8
          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>UTF-8</encoding>
                </configuration>
          </plugin>
и в седьмых если использую tomcat то настраиваю Connector параметром URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" URIEncoding="UTF-8"/>
если использую подключение к БД настраиваю передачу и хранение данных в нужной кодировке. И так локализация приложения это комплексное действие при котором нужно настраивать всЁ приложение на работу с определенной кодировкой, в моем случае используется - UTF-8.
 source code

Комментариев нет:

Отправить комментарий