자바의 스프링을 사용한 플랫폼에서 국제화 i18n / fmt:message vs spring:message

반응형

http://java.sun.com/jsp/jstl/core

fmt:message vs spring:message

자바의 스프링을 사용한 플랫폼에서 국제화 i18n 을 고려하려면 대표적으로 두가지 방법이 있습니다.

1. jstl 에서 제공하는 기본적인 fmt: 의 경우 다음과 같이 사용합니다.

<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″ isELIgnored=”false”%><%@ taglib
prefix=”c” uri=”http://java.sun.com/jsp/jstl/core”%><%@ taglib prefix=”d”
uri=”http://www.opensymphony.com/sitemesh/decorator”%><%@ taglib prefix=”fmt” uri=”http://java.sun.com/jsp/jstl/fmt”%><%@ taglib
prefix=”fn” uri=”http://java.sun.com/jsp/jstl/functions”%>
<fmt:requestEncoding value=”UTF-8″ />
<fmt:setLocale value=”ko” scope=”session” />
<fmt:setBundle basename=”message” />

http://yeonicon.tistory.com/670



2. spring MVC 에서 제공하는 spring: 의 경우 다음과 같이 사용합니다.

<bean class=”org.springframework.context.support.ReloadableResourceBundleMessageSource” id=”messageSource” p:basenames=”WEB-INF/i18n/messages,WEB-INF/i18n/application” p:fallbackToSystemLocale=”false”/>

와 같이 빈을 등록해주고

리소스 번들은 어짜피 스프링 Application Context에서 가지고 오는 것이니 XML이나 .properties 파일 둘 다 지원합니다.

http://dev.anyframejava.org/anyframe/doc/web/3.0.1/webfw/springmvc/basic/locale.html

http://charmpa.egloos.com/2922469

http://yeonicon.tistory.com/653

http://blog.naver.com/PostView.nhn?blogId=rock1191&logNo=60195762032

http://howtodoinjava.com/2013/07/26/internationalization-i18n-support-in-spring-3-example-tutorial/

http://viralpatel.net/blogs/spring-3-mvc-internationalization-i18n-localization-tutorial-example/

http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/

http://stackoverflow.com/questions/15190101/spring-mvc-i18n-springmessage-gives-jasperexception-no-message-found-under

http://www.jroller.com/raible/entry/spring_mvc_s_reloadableresourcebundlemessagesource

http://www.journaldev.com/1370/java-internationalization-i18n-example-tutorial

http://www.uniorder.com/category/spring-framwork/

http://ecspecialist.tistory.com/entry/Spring-message-태그를-이용한-메세지-관리

http://blog.naver.com/PostView.nhn?blogId=pureb612b&logNo=10120505318

http://changpd.blogspot.com.au/2013/05/localeresolver-messagesource.html

http://templth.wordpress.com/2010/07/21/configuring-locale-switching-with-spring-mvc-3/

spring:message 에는 fmt:message에 없는 몇가지 속성이 더 있습니다.
일단 fmt:message에는

key
bundle
var
scope

이렇게 네가지가 있구요.

spring:message에는 다음 7가지가 있습니다.

code : fmt:message의 key에 해당
arguments: 리소스 번들의 메시지에 {0}, {1} 같은 기호 자리에 들어갈 값을 나열
argumentSeparator: arguments 속성에 값을 구분하는 기호, 기본은 콤마(‘,’)
text: code에 해당하는 메시지가 리소스 번들에 없을 때 사용될 메시지
message: MessageSourceResolvable 인터페이스를 구현한 객체 또는 MessageSourceResolvable를 나타내는 spel 식. 에러 메시지를 표시하려고 한다면 필요하겠죠.
htmlEscape: true일 때 HTML 엔티티를 인코딩
javaScriptEscape: true일 때 자바스크립트 문자열로 인코딩
var: fmt:message와 동일
scope: fmt:message와 동일



파라미터 넘기는 방식이 fmt:message는

<fmt:message key=”main_hello”>
<fmt:param>benelog</fmt:param>
</fmt:message>
인 반면에 spring:message는 좀 더 간결하게
<spring:message code=”main_hello” arguments=”benelog!”/><br/>
되어서 더 좋은 점도 있네요.
그리고 위에서 말씀드린 것처럼 명시적인 에러반환 등 spring:message가 더 좋은 점이 있어보입니다.


* 삼성 SDS 의 anyframe 의 경우 자체 tld 정의하여 사용하기도 합니다.

이는 properties 파일을 사용하면서도 유니코드 변환 없이 사용할 수 있도록 해줍니다.

<%@ taglib uri=’/WEB-INF/anyframe-message.tld’ prefix=’anyframe’ %>

prefix 를 anyframe 으로 정의할 경우 다음과 같이 사용.

<anyframe:message code=”error.get.userList” />



native2ascii.exe 는 jdk 의 bin 디렉토리에 기본적으로 들어있습니다.

C:\Program Files\Java\jdk1.6.0_45\bin\native2ascii.exe -encoding utf-8
D:\Project\simplely\web\src\main\resources\message_kr_original.properties
D:\Project\simplely\web\src\main\resources\message_kr.properties

와 같은 명령어로 변환이 가능합니다.



Properties에 loadFromXML(…)이 생긴 걸로 인해 자바 5에 대한 고마움이 한층 커었죠.
자바 5는 여러모로 자바 개발자에게 축복이었습니다.

언어적으로 여러가지로 개선된 자바 7도 얼른 보급됐으면 좋겠고 람다식이 들어갈 예정인 자바 8도 이쁘게 잘 나오면 좋겠네요.



properties 설정 파일 자체가 국제화를 고려하지 않는 오래된 방식입니다. 아래 글 참조.

http://kwon37xi.egloos.com/4665590





http://lusiea.tistory.com/entry/JSP-JSTL-fmt태그-국제화-지역화-태그

http://valley.egloos.com/viewer/?url=http%3A%2F%2Firis2380.egloos.com%2F423265

http://www.tutorialspoint.com/jsp/jstl_format_message_tag.htm

http://blog.naver.com/PostView.nhn?blogId=wonminst&logNo=90096500137&categoryNo=51&viewDate¤tPage=1&listtype=0

http://labs.teppefall.com/2011/05/jsp_jstl_fmt_utf-8_unicode_and_native2ascii.html





messages.properties 파일들을 일일이 각자 수정하여 카피하고 하면 관리가 힘이 듭니다. 이때 ResourceBundle Editor 라는 이클립스 플러그인을 사용하면 쉽게 관리할 수 있습니다.

http://ecspecialist.tistory.com/entry/eclipse-plug-in-ResourceBundle-Editor

http://sourceforge.net/projects/eclipse-rbe/





language 셀렉터를 만드는 법

아마 일반적으로 footer 영역에 한국어/english … 와 같이 언어선택을 할 수 있는 셀렉터를 만들 것입니다. 스프링의 기본적인 spring:message 태그 사용할 경우 그리고 spring-mvc 를 사용할 경우에는 localeIntercepter 를 사용하여 ?lang=en / ?lang=ko 와 같이 url 을 던져주는 식으로 사용할 수도 있고, localeResolver 의 종류에 따라 Cookie 나 Session 등을 변경해 주어야 할 경우도 있습니다.

UI 단에서는

<script type=”text/javascript”>
$(document).ready(function() {
var cookieLang = $.cookie(‘lang’);
if(cookieLang == “ko”) {
$(“#dropdown-lang”).html(“한국어”);
}
if(cookieLang == “en”) {
$(“#dropdown-lang”).html(“English”);
}

$(‘.language-switch’).click(function() {
var lang = $(this).attr(‘data-id’);

$.cookie(‘lang’, lang);
// refresh the page.
window.location.reload(true);
});
});
</script>



<li class=”btn-group”>
<button class=”btn btn-default btn-xs dropdown-toggle” type=”button” data-toggle=”dropdown”>
<span id=”dropdown-lang”>English</span> <!– ${pageContext.response.locale} –><span class=”caret”></span>
</button>
<ul class=”dropdown-menu”>
<li>
<a href=”#” class=”language-switch” data-id=”en”>English</a>
<a href=”#” class=”language-switch” data-id=”ko”>한국어</a>
</li>
</ul>
</li>



이러한 방식으로 구성할 수 있습니다. jstl 기본 fmt 태그 사용시에는

<fmt:requestEncoding value=”UTF-8″ />
<fmt:setBundle basename=”messages” />
<c:choose>
<c:when test=”${not empty param.lang}”>
<fmt:setLocale value=”${param.lang}” scope=”session” />
</c:when>
<c:when test=”${not empty cookie.lang}”>
<fmt:setLocale value=”${cookie.lang.value}” scope=”session” />
</c:when>
<c:when test=”${not empty sessionScope.lang}”>
<fmt:setLocale value=”${sessionScope.lang}” scope=”session” />
</c:when>
<c:otherwise>
<fmt:setLocale value=”ko” scope=”session” />
</c:otherwise>
</c:choose>

이런식으로 사용할 수 있습니다.



* spring-webmvc 를 사용하지 않을 경우.

스프링 웹 MVC 를 사용하지 않고 jersey 만을 사용한다거나 할 경우 localeResolver 를 applicationContext.xml 에

<bean id=”localeResolver”
class=”org.springframework.web.servlet.i18n.CookieLocaleResolver”>
<property name=”defaultLocale” value=”en” />
<property name=”cookieName” value=”lang” />
<property name=”cookieMaxAge” value=”100000″/>
<property name=”cookiePath” value=”web/cookie”/>
</bean>

이런식으로 등록해 주어도 스프링 MVC 의 Dispatcher 서블릿에서 localeResolver 를 가져와서 사용하는 형식이기 때문에 위의 localeResolver 를 등록하여도 Dispatcher 서블릿을 통한 웹앱이 아닌이상 언어 변환이 이루어지지 않고 마치 디폴트로 설정되는AcceptHeaderLocaleResolver 을 사용하는 듯한 결과만을 보여줍니다. 아래는 스프링 MVC 구성에 필요한 파일들.

commons-logging-1.0.4.jar
jstl-1.2.jar
org.springframework.asm-3.0.1.RELEASE-A.jar
org.springframework.beans-3.0.1.RELEASE-A.jar
org.springframework.context-3.0.1.RELEASE-A.jar
org.springframework.core-3.0.1.RELEASE-A.jar
org.springframework.expression-3.0.1.RELEASE-A.jar
org.springframework.web.servlet-3.0.1.RELEASE-A.jar
org.springframework.web-3.0.1.RELEASE-A.jar

DispatcherServlet.java 의 소스를 보면 아래와 같은 부분이 있습니다.

public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
기본적으로는 localeResolver 라는 id 를 가진 빈을 ApplicationContext 에서 가져옵니다.





아래도 jsp 공통 페이지에 입력하여 사용하면 좋은 코드.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
<%@ taglib prefix='fmt' uri='http://java.sun.com/jsp/jstl/fmt' %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page isELIgnored="false" %>
<%-- first check if the request variable has been set --%>
<%-- second check if there is a session variable --%>
<%-- third check if there is a cookie --%>
<%-- fourth check the browser header --%>
<c:choose>
<c:when test="${!empty param.locale}">
<!-- 1: get locale from the request parameter -->
<c:set var="locale" scope="session" value="${param.locale}" />
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${empty cookie.locale.value}">
<!-- 4: get locale from the browser header 'Accept-Language' -->
<c:set var="locale" scope="session" value="${fn:substringBefore(fn:substringBefore(header['Accept-Language'],','),'-')}" />
</c:when>
<c:otherwise>
<!-- 3: get the locale from the cookie -->
<c:set var="locale" scope="session" value="${cookie.locale.value}"/>
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
<!-- setting session variable and cookie locale=${locale} -->
<fmt:setLocale scope="session" value="${locale}" />
<%
Cookie localeCookie = new Cookie("locale", (String)session.getAttribute("locale"));
localeCookie.setMaxAge(0x7ffffff);
response.addCookie(localeCookie);
%>
<%-- <c:set var="cookie.locale.value" value="${locale}" /> --%>

반응형

댓글

Designed by JB FACTORY