본문 바로가기
Java . Spring . Web . SQL

다국어 처리 : 메시지파일, MessageSource 등록, LocaleResolver 등록, Locale 변경

by heidish 2020. 10. 22.
반응형

 

 

 

 

 

 

 

 

다국어 처리

 

 

스프링에서 제공하는 다국어 처리 방식은 스프링 이전에 등장했던 Struts 프레임워크와 매우 유사하다.

 

그리고 사용자가 원하는 언어로 화면이나 메시지를 출력해주기 위해서는

각 언어에 따른 메시지 파일을 모두 작성해야 한다.

 

기본적으로 메시지 파일의 확장자  " .properties " 이며,

파일명은 해당 언어의 Locale 정보를 이용해 작성해준다.

 

ex )  messageSource_en.properties

 

 

 


 

 

 

여태 만든 프로젝트에 다국어 처리를 해줄껀데

영어, 한국 두 가지 언어로 해줄꺼다,,,,

 

 

 


1.  영어 메시지파일 생성

 

 

영어, 한글 각각의 메시지 파일을 먼저 만들어야하는데,

 아래와 같이  src/main/resources  소스폴더 내부에 패키지를 먼저 생성하자.

 

 

그리고 이 message 라는 패키지에서 마우스 우클릭 후, Other > General > File 선택 후

파일 이름을 입력하고 Finish 클릭하기!

 

영어 메시지 파일을 먼저 만들꺼라서,  파일명을  messageSource_en.properties  로 해줬다.

 

 

( messageSource_en.properties )

# login.jsp
message.user.login.title=LOGIN
message.user.login.id=ID
message.user.login.password=PASSWORD
message.user.login.loginBtn=LOG-IN

message.user.login.language.en=English
message.user.login.language.ko=Korean

# getBoardList.jsp
message.board.list.mainTitle=BOARD LIST
message.board.list.welcomeMsg=! Welcome to my BOARD
message.board.list.search.condition.title=TITLE
message.board.list.search.condition.content=CONTENT
message.board.list.search.condition.btn=Search
message.board.list.table.head.seq=SEQ
message.board.list.table.head.title=TITLE
message.board.list.table.head.writer=WRITER
message.board.list.table.head.regDate=REGDATE
message.board.list.table.head.cnt=CNT
message.board.list.link.insertBoard=Insert Board

( 참고로 # 은 주석처리할 때 사용한다. )

 

 

이렇게 영어 메시지 파일을 프로퍼티 파일로 만드는건 괜찮은데,

한글 등 아시아권의 언어의 경우 반드시 유니코드로 변환해서 등록해야 한다.

 

 

우리는 자바 JDK 의 bin 에 들어있는 native2ascii.exe 를 이용해서 변환해줄꺼다 !

 

 


 

1.  한글 메시지파일 생성

 

 

먼저 메모장을 켜고, 영어 메시지 파일을 사용할 때 작성한 내용을 복사, 붙여넣기 한 뒤

아래와 같이 값들을 한글로 바꿔서 써준다.

 

 

( messageSource_ko.txt )

# login.jsp
message.user.login.title=로그인
message.user.login.id=아이디
message.user.login.password=비밀번호
message.user.login.loginBtn=로그인

message.user.login.language.en=영어
message.user.login.language.ko=한글

# getBoardList.jsp
message.board.list.mainTitle=게시글 목록
message.board.list.welcomeMsg=님! 게시판에 오신걸 환영합니다.
message.board.list.search.condition.title=제목
message.board.list.search.condition.content=내용
message.board.list.search.condition.btn=검색
message.board.list.table.head.seq=번호
message.board.list.table.head.title=제목
message.board.list.table.head.writer=작성자
message.board.list.table.head.regDate=등록일
message.board.list.table.head.cnt=조회수
message.board.list.link.insertBoard=새글 등록

 

그리고 저장하는데, 확장자는 그대로 txt 파일 형태로 저장하고, 파일명은 한국 Locale 정보를 이용해서

messageSource_ko.txt  이렇게 저장해주자.

 

 

저장할 때 주의할 점은, 우리는 cmd 창을 통해 이 txt 파일의 위치를 찾아야 하기 때문에

파일의 경로를 알기 쉽도록 설정해주자.

 

 

나는  C:\Users\admin\unicode  이 위치에 저장해줬다.

(admin 폴더 내에 unicode 라는 폴더를 새로 만들고 여기에 txt 파일을 넣어줬음)

 

 

그리고 cmd 창을 키고 아래와 같이 해당 경로로 이동한다.

 

 

cd C:\Users\admin\unicode  까지 입력 후 엔터 !

 

 

그러면 이렇게 unicode 폴더 내로 이동했다고 뜬다.

여기서  native2ascii messageSource_ko.txt messageSource_ko.properties  입력하기 (띄어쓰기 주의!)

native2ascii messageSource_ko.txt messageSource_ko.properties

 

그러면 아래 cmd 창은 아래와 같이 되고,

 

unicode 라는 폴더로 실제 들어가보면

해당 txt 파일명과 동일한 파일명의 properties 파일이 생성된걸 볼 수 있다.

 

 

이제 확인차 해당 properties 파일을 "메모장을 이용해서" 열어보면,

# login.jsp
message.user.login.title=\u6fe1\uc493\ub807\ufffd\uc524
message.user.login.id=\ufffd\ube18\ufffd\uc520\ufffd\ubd52
message.user.login.password=\u936e\uafa8\ufffd\u8e30\ub34a\uc0c7
message.user.login.loginBtn=\u6fe1\uc493\ub807\ufffd\uc524

message.user.login.language.en=\ufffd\uc07a\ufffd\ubf31
message.user.login.language.ko=\ufffd\ube33\u6e72\ufffd

# getBoardList.jsp
message.board.list.mainTitle=\u5bc3\ub6af\ub586\u6e72\ufffd \uf9cf\u2478\uc909
message.board.list.welcomeMsg=\ufffd\ub582! \u5bc3\ub6af\ub586\ufffd\ub64b\ufffd\ubfc9 \ufffd\uc0a4\ufffd\ub58a\u5ac4\ufffd \ufffd\uc19a\ufffd\uc07a\ufffd\ube40\ufffd\ub572\ufffd\ub58e.
message.board.list.search.condition.title=\ufffd\uc823\uf9cf\ufffd
message.board.list.search.condition.content=\ufffd\uada1\ufffd\uc29c
message.board.list.search.condition.btn=\u5bc3\ufffd\ufffd\uae4b
message.board.list.table.head.seq=\u8e30\ub34a\uc0c7
message.board.list.table.head.title=\ufffd\uc823\uf9cf\ufffd
message.board.list.table.head.writer=\ufffd\uc609\ufffd\uaf66\ufffd\uc604
message.board.list.table.head.regDate=\ufffd\ubc91\u6fe1\uc579\uc52a
message.board.list.table.head.cnt=\u8b70\uace0\uc276\ufffd\ub2d4
message.board.list.link.insertBoard=\ufffd\uae49\u6e72\ufffd \ufffd\ubc91\u6fe1\ufffd

이렇게 유니코드로 변환된걸 볼 수 있다.

 

 

이 properties 파일을 복사해서 아까 sts 의 프로젝트 내에 만든 message 패키지에 붙여넣기 하면 된다.

 

 


 

이렇게 원하는 언어들의 메시지 파일을 다 작성했다면,

스프링 설정 파일에 해당 메시지 파일들을 읽어들일 수 있도록 MessageSource 클래스를 <bean> 등록 해야한다.

 

 

( presentation-layer.xml )

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!-- component scan Registration : Controller's -->
	<context:component-scan base-package="com.heidi.view"></context:component-scan>
	
	<!-- File Upload Configuration : CommonsMultipartResolver -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="100000"></property>
	</bean>
	
	<!-- XML Exception Process -->
	<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="java.lang.ArithmeticException">
					common/arithmeticError.jsp
				</prop>
				<prop key="java.lang.NullPointerException">
					common/nullPointerError.jsp
				</prop>
			</props>
		</property>
		<property name="defaultErrorView" value="common/error.jsp"/>
	</bean>
	
	<!-- MessageSource Configuration -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basenames">
			<list>
				<value>message.messageSource</value>
			</list>
			<!-- 
				<value>message.messageSource_en.properties</value>
				<value>message.messageSource_ko.properties</value>
			 -->
		</property>
	</bean>
	
</beans>

전체 코드는 이런데, 이중에서 지금 등록한 부분인 MessageSource 클래스 관련 <bean> 태그만 보면,

<!-- MessageSource Configuration -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>message.messageSource</value>
		</list>
		<!-- 
			<value>message.messageSource_en.properties</value>
			<value>message.messageSource_ko.properties</value>
		-->
	</property>
</bean>

이렇다 !

 

<bean> 태그의 class 속성값에 있는 ResourceBundleMessageSource 클래스가

src/main/resources 폴더를 건드리게 되는데, 이에 대한 id 값 또한 고정값이므로 맘대로 바꾸면 안된다.

 

그리고 내부의 <property> 엘리먼트의 name 속성에는 두 가지 값이 존재한다.

basename & basenames 의 두가지!

근데 우리는 하나의 언어가 아닌 두가지 언어, 즉 여러가지 언어를 등록할꺼라서 basenames 를 사용해야 한다.

 

 

 

 

근데 생각해보면 <value> 값에는 중간에 <!-- --!> 로 주석처리한 부분의 <value> 값처럼 써야 할 것 같은데,

왜 죄다 생략하고 저렇게 하나의 value 값만 써준거지?

 

 

 

 

이에 대한 답은, 우선 MessageSource 에 메시지 파일을 등록할 때, 확장자인 " .properties " 는 생략한다 !

이건 Struts 프레임워크때부터 적용된 규칙으로, 아주 만약에 확장자가 존재하지 않고 그저 파일명이 "properties" 인 파일이 존재할 가능성도 있고 등등의 이유로 생략하기로 한 것이다,,

 

그리고 

message.messageSource_en 에서 뒤의  _en 그리고 _ko 를 생략한 이유는,

메시지 파일을 좀 더 효율적으로 관리하기 위함이라고 한다.

 

일반적으로 화면에서 사용할 메시지를 하나의 파일에 모두 작성하는 경우는 없고,

여러개의 파일에 나누어서 관리하는데, 일반적으로는 컴포넌트 하나당 하나의 메시지 파일을 작성하게 된다.

 

근데 만약 시스템에 10 개의 컴포넌트가 존재하고, 총 5개의 언어를 지원하게 만든다고 가정해보면

총 50개의 메시지 파일이 등록되야 한다....후덜..ㅎ

 

그래서 스프링에서는 언어에 해당하는 정보를 메시지 파일에서 제거하는 방법을 선택했다고 한다,,

 

이렇게하면 컴포넌트당 하나의 메시지 파일만 등록하면 되고,

새 언어가 추가 또는 삭제된다 해도 스프링설정파일을 수정할 필요가 없기 때문!

 

다만, 어떤 메시지파일이 적용될지는 기본언어설정 & Locale변화 에 따라서 자동으로 언어메시지가 선택된다.

 

 

 

 


 

 

 

LocaleResolver 등록

 

 

웹 브라우저가 서버에 어떠한 요청을 보내게되면, 기본 브라우저의 Locale 정보가 HTTP 요청 메시지 헤더에

자동으로 설정된 상태로 전송이 되게 된다.

 

이 때, 스프링은 LocaleResolver 를 통해서 클라이언트의 Locale 정보를 추출하고,

추출한 Locale 정보에 해당하는 언어의 메시지를 적용시켜 보여준다.

 

 

스프링은 4 개의 LocaleResolver 를 지원하는데,

만약 스프링 설정 파일에 LocaleResolver가 따로 등록된게 아니라면 기본값으로

AcceptHeaderLocaleResolver가 적용된다.

 

 

 


 

 

스프링이 제공하는 LocaleResolver 종류

 

 

AcceptHeaderLocaleResolver

-   기본값

-   브라우저에서 전송된 HTTP 요청 헤더에서 Accept-Language에 설정된 Locale로 메시지를 적용함

 

CookieLocaleResolver

-   Cookie 에 저장된 Locale 정보를 추출해서 메시지를 적용

 

SessioLocaleResolver

-   HttpSession에 저장된 Locale 정보를 추출해서 메시지를 적용

-   가장 많이 사용함 !

 

FixedLocaleResolver

-   웹 요청과 무관하게 특정 Locale로 고정함

 

 

 

 


 

이제 계속해서 LocaleResolver 를 등록 해 볼껀데,

우리는 SessionLocaleResolver 를 등록해보자.

 

 

 

( presentation-layer.xml )

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!-- component scan Registration : Controller's -->
	<context:component-scan base-package="com.heidi.view"></context:component-scan>
	
	<!-- File Upload Configuration : CommonsMultipartResolver -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="100000"></property>
	</bean>
	
	<!-- XML Exception Process -->
	<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="java.lang.ArithmeticException">
					common/arithmeticError.jsp
				</prop>
				<prop key="java.lang.NullPointerException">
					common/nullPointerError.jsp
				</prop>
			</props>
		</property>
		<property name="defaultErrorView" value="common/error.jsp"/>
	</bean>
	
	<!-- MessageSource Configuration -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basenames">
			<list>
				<value>message.messageSource</value>
			</list>
			<!-- 
				<value>message.messageSource_en.properties</value>
				<value>message.messageSource_ko.properties</value>
			 -->
		</property>
	</bean>
	
	<!-- LocaleResolver Registration -->
	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
	
	<!-- LocaleChangeInterceptor Registration -->
	<mvc:interceptors>
		<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
			<property name="paramName" value="lang"/>
		</bean>
	</mvc:interceptors>
	
</beans>

전체코드고, 이 중에서 SessionLocaleResolver 관련 설정만 뽑아서 보면 아래 코드부분이니 참고하자.

 

 

 

 

 

<!-- LocaleResolver Registration -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>

주의할점은 다른 Resolver 들과 마찬가지로,

LocaleResolver 또한 고정된 id 값을 가진다는 것 !

여기서 id 값을 localeResolver 가 아닌 다른값으로 넣으면 다국어 처리가 작동하지 않는다.

 

 

 

 

 

 

그리고 특정 언어로 화면을 보다가 다른 언어로 변경해서 보고 싶을 때는

( ex. 영어로 된 화면을 보다가 한국어로 된 화면으로 변경하고 싶을 때 )

스프링이 제공하는 LocaleChangeInterceptor 클래스를 사용한다.

 

이 클래스는 HandlerInterceptor 인터페이스를 구현한 클래스로,

아래와 같이 스프링설정파일에 인터셉터로 등록해야한다.

<!-- LocaleChangeInterceptor Registration -->
<mvc:interceptors>
	<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName" value="lang"/>
	</bean>
</mvc:interceptors>

주의 할 점은, <beans> 루트 엘리먼트에 mvc 네임스페이스가 추가된 상태여야 <mvc:interceptors> 엘리먼트를 사용할 수 있고, 이로써 LocaleChangeInterceptor 객체를 인터셉터로 등록할 수 있다는 것 !

 

그리고 LocaleChangeInterceptor 를 등록할 때, Setter 주입으로 paramName 값을 "lang" 으로 저장했는데,

이는 클라이언트로부터 lang 이라는 파라미터로 특정 Locale이 전송되면 해당 Locale로 변경하겠다는 설정이다.

 

 

 


 

여기까지 설정했으면 jsp 를 수정해야 한다.

 

우선 스프링에서 제공하는 태그 라이브러리를 사용해야 하는데,

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

이와 같이 JSP 파일 상단에 taglib 지시자를 페이지 지시자 아래에 써줘야한다.

 

그리고 아래와 같이 <spring:message /> 태그의 code 속성값으로

메시지 파일에 등록된 메시지 key 를 등록하면 Locale에 해당하는 메시지를 출력할 수 있다.

<spring:message code="메시지 키 값" />

 

 

 

( login.jsp )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><spring:message code="message.user.login.title"/></title>
</head>

<body align="center">
	<h1><spring:message code="message.user.login.title"/></h1>
	<a href="login.do?lang=en">
		<spring:message code="message.user.login.language.en"/>
	</a>&nbsp;&nbsp;
	<a href="login.do?lang=ko">
		<spring:message code="message.user.login.language.ko"/>
	</a>
	<hr>
	
	<div align="center">
	<form action="login.do" method="post">
		<table border="1" cellpadding="0"  cellspacing="0">
			<tr>
				<td bgcolor="orange">
					<spring:message code="message.user.login.id"/>
				</td>
				<td>
					<input type="text" name="id" value="${user.id }"/>
				</td>
			</tr>
			
			<tr>
				<td bgcolor="orange">
					<spring:message code="message.user.login.password"/>
				</td>
				<td>
					<input type="password" name="password" value="${user.password }"/>
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="submit" value="<spring:message code="message.user.login.loginBtn"/>" />
				</td>
			</tr>
		</table>
	</form>
	</div>
</body>
</html>

 

그리고 getBoardList.jsp 또한 바꿔주자.

 

 

( getBoardList.jsp )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><spring:message code="message.board.list.mainTitle"/></title>
</head>

<body align="center">
	<h1><spring:message code="message.board.list.mainTitle"/></h1>
	<h3>${userName}<spring:message code="message.board.list.welcomeMsg"/>
		<a href="logout.do">Log-out</a>
	</h3>
	
	<!-- 검색 시작 -->
	<div align="center">
	<form action="getBoardList.do" method="post">
		<table border="1" cellpadding="0"  cellspacing="0" width="700">
			<tr>
				<td align="right">
					<select name="searchCondition">
						<c:forEach items="${conditionMap }" var="option">
							<option value="${option.value }">${option.key }
						</c:forEach>
					</select>
					
					<!-- 기존 검색 코드
					<select name="searchCondition">
						<option value="TITLE">제목</option>
						<option value="CONTENT">내용</option>
					</select>
					 -->
					<input type="text" name="searchKeyword" />
					<input type="submit" value="<spring:message code="message.board.list.search.condition.btn"/>">
				</td>
			</tr>
		</table>
	</form>
	<!-- 검색 종료 -->
	
	<table border="1" cellpadding="0"  cellspacing="0" width="700" >
		<tr>
			<th bgcolor="orange" width="100" >
				<spring:message code="message.board.list.table.head.seq"/>
			</th>
			<th bgcolor="orange" width="200">
				<spring:message code="message.board.list.table.head.title"/>
			</th>
			<th bgcolor="orange" width="150">
				<spring:message code="message.board.list.table.head.writer"/>
			</th>
			<th bgcolor="orange" width="150">
				<spring:message code="message.board.list.table.head.regDate"/>
			</th>
			<th bgcolor="orange" width="100">
				<spring:message code="message.board.list.table.head.cnt"/>
			</th>
		</tr>
		
		<c:forEach items="${boardList }" var="board">
		<tr>
			<td align="center">${board.seq }</td>
			<td align="left">&nbsp;&nbsp;<a href="getBoard.do?seq=${board.seq }">${board.title }</a></td>
			<td align="center">${board.writer }</td>
			<td align="center">${board.regDate }</td>
			<td align="center">${board.cnt }</td>
		</tr>	
		</c:forEach>

	</table>
	
	</div>	
	<br />
	<a href="insertBoard.jsp">
		<spring:message code="message.board.list.link.insertBoard"/>
	</a>
</body>
</html>

 

 

 


 

 

실행 결과,

 

 

기본적으로 로그인 화면이 이렇게 뜨고, 여기서 상단의 "영어" 를 누르면

이렇게 바뀌게 된다.

 

영어로 바꾼 상태로 "로그인" 을 해보면

영어로 잘 바뀐걸 확인할 수 있다.

 

 

 

 

 

 

 

반응형

댓글