티스토리 뷰

프로그래밍/Web

Spring 다국어 처리

국윤창 2019. 9. 24. 20:22

Spring은 Locale에 따라 다국어 메시지 처리를 위해 MessageSource라는 이름의 전략 인터페이스를 제공해준다. 이번 글에서는 MessageSource를 이용해 다국어 처리를 하는 방법을 알아보자

 

MessageSource

Spring이 메시지를 가져올 때 사용하는 MessageSource의 구현체는 아래 두 가지가 있다.

 

  • ResourceBundleMessageSource: 리소스 번들(properties 파일)로 부터 메시지를 읽는다.
  • ReloadableResourceBundleMessageSource: 리소스 번들이 수정되면 애플리케이션을 재시작하지 않고 다시 로딩하여 메시지를 읽는다.

Spring에서 MessageSource 객체를 사용하기 위해선 아래와 같이 "messageSource"라는 이름으로 Bean을 등록해야 한다.

/**
 * 프로퍼티로부터 메시지를 읽기위한 MessageSource
 *
 * @return MessageSource 객체
 */
@Bean
public MessageSource messageSource() {
	ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
	messageSource.setDefaultEncoding("UTF-8");
	messageSource.setBasename("messages/message");
	return messageSource;
}

Spring은 MessageSource Bean을 "messageSource"라는 이름으로 찾는데, 만약 찾지 못하면 비어있는 MessageSource 객체인 DelegatingMessageSource 객체를 빈으로 가져와 사용하게 된다.

 

아래 그림 1은 "messageSource" 대신 "ms"라는 이름으로 MessageSource 객체를 Bean으로 등록했을 때 주입된 객체를 보여준다.

[그림 1] DelegatingMessageSource

그리고 아래 그림 2는 "messageSource"라는 이름으로 MessageSource 객체를 Bean으로 등록했을 때, 정상적으로 주입되는 객체를 보여준다.

[그림 2] ResourceBundleMessageSource

위와 같이 정의된 ResourceBundleMessageSource Bean은 메시지를 참조할 파일을 찾을 때 Spring의 ResourceBundle 규칙을 따르게 된다. 중요한 것 몇 가지만 적자면 아래와 같다.

 

  • 하나의 ResourceBundle은 동일한 패키지 or 폴더 내에 동일한 공통 이름을 가져야한다. ResourceBundleMessageSource는 basename에 명시된 경로의 파일을 참조하게 된다.
    위에서 Bean으로 등록한 MessageSource의 경우, 클래스 패스의 messages 폴더 안에 message 라는 공통이름을 가진 리소스를 참조하게 된다.
  • 리소스를 Locale 별로 구분하기 위해선, Locale 코드를 공통 이름에 밑줄 기호와 함께 더해야한다.
    예를 들면, message_ko.properties, message_en.properties 와 같이 리소스를 Locale 별로 구분할 수 있다.

 

MessageSource Test

이제 MessageSource를 테스트 하기 위한 환경을 준비해보겠다. 아래 그림 3, 4와 같이 Locale 별로 구분된 리소스를 만들어 보자.

[그림 3] Locale 별 리소스
[그림 4] 메시지 코드

 

그림 3, 4에 구성된 message 리소스 번들은 "test.message1"이라는 메시지 코드를 공통으로 가지고 있다. 이 코드에는 각 국가별 "안녕하세요" 메시지가 유니코드로 저장돼있다. MessageSource의 기본 인코딩을 UTF-8로 해놓았으므로, 유니코드로 저장 해야한다.

 

이제 테스트 코드를 작성해보자. 아래 코드는 MessageSource로부터 사전 정의된 메시지를 Locale 별로 잘 가져오는지 테스트하는 것이다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class MessageSourceTest {
	private static final Logger LOGGER = LoggerFactory.getLogger(MessageSourceTest.class);
	private static final String MESSAGE_CODE = "test.message1";
	private static final String DEFAULT_LOCALE_MESSAGE = "\uC548\uB155\uD558\uC138\uC694";
	private static final String KOREA_LOCALE_MESSAGE = "\uC548\uB155\uD558\uC138\uC694";
	private static final String ENGLISH_LOCALE_MESSAGE = "\u0048\u0065\u006C\u006C\u006F";
	private static final String JAPANESE_LOCALE_MESSAGE = "\u3053\u3093\u306B\u3061\u306F";
	private static final String CHINESE_LOCALE_MESSAGE = "\u4F60\u597D";

	@Autowired
	private MessageSource messageSource;

	@Test
	public void getDefaultMessageTest() {
		String message = messageSource.getMessage(MESSAGE_CODE, null, Locale.getDefault());
		LOGGER.debug("Default locale message: {}", message);
		assertEquals(DEFAULT_LOCALE_MESSAGE, message);
	}

	@Test
	public void getMessageByLocaleTest() {
		// korea
		String message = messageSource.getMessage(MESSAGE_CODE, null, Locale.KOREAN);
		LOGGER.debug("Korean message: {}", message);
		assertEquals(KOREA_LOCALE_MESSAGE, message);

		// english
		message = messageSource.getMessage(MESSAGE_CODE, null, Locale.ENGLISH);
		LOGGER.debug("English message: {}", message);
		assertEquals(ENGLISH_LOCALE_MESSAGE, message);

		// japanese
		message = messageSource.getMessage(MESSAGE_CODE, null, Locale.JAPANESE);
		LOGGER.debug("Japanese message: {}", message);
		assertEquals(JAPANESE_LOCALE_MESSAGE, message);

		// chinese
		message = messageSource.getMessage(MESSAGE_CODE, null, Locale.CHINESE);
		LOGGER.debug("Chinese message: {}", message);
		assertEquals(CHINESE_LOCALE_MESSAGE, message);
	}
}

 

테스트를 돌려 성공하면 MessageSource가 Locale 별로 메시지를 잘 가져오는 것이다.

 

Spring Message Tag

JSP에서 MessageSource를 이용해 Locale 별로 메시지를 얻어오려면 Spring의 tags 라이브러리를 사용하면 된다. tags 라이브러리의 message 태그는 Spring의 Context로부터 MessageSource 객체를 얻어와 메시지 코드에 따라 메시지를 가져온다.

 

아래 코드는 위에서 정의한 메시지를 가져와 간단히 보여주는 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>Multi Language Test</title>
</head>
<body>
    <h1>Multi Language Test</h1>
    <p>Message: <spring:message code="test.message1"/></p>
</body>
</html>

 

위 페이지를 접속하면 아래 그림 5, 6과 같이 Locale에 따라 메시지를 보여준다.

[그림 5] Locale en의 화면
[그림 6] Locale ja의 화면

 

브라우저는 Locale을 내장하고 있는데, 이에 따라서 서버에서 Locale에 따른 메시지를 보여주게 된다. 이 Locale은 Accept-Language HTTP 헤더에 담겨 서버에 전달된다. 만약 브라우저의 Locale을 변경하여 테스트해보고 싶다면, Locale Switcher 같은 크롬 확장프로그램을 이용해 테스트해보길 바란다.

 


참고

MessageSource in Spring Reference

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#context-functionality-messagesource

 

Core Technologies

Letting qualifier values select against target bean names, within the type-matching candidates, does not require a @Qualifier annotation at the injection point. If there is no other resolution indicator (such as a qualifier or a primary marker), for a non-

docs.spring.io

ResourceBundle

https://www.baeldung.com/java-resourcebundle

 

A Guide to the ResourceBundle | Baeldung

It's always challenging to maintain and extend multilingual applications. This article covers how to use the ResourceBundle to cope with the varieties that come up when you need to provide the same

www.baeldung.com

Unicode 변환기

http://www.hipenpal.com/tool/characters-to-unicode-converter-in-korean.php

 

유니코드 변환기 - Hi!Penpal!

문자를 유니코드(Unicode)로 변환/변경해주는 툴입니다.

www.hipenpal.com

 

'프로그래밍 > Web' 카테고리의 다른 글

Spring 다국어 처리  (0) 2019.09.24
Spring Validation  (8) 2019.06.13
webpack 정리  (0) 2019.03.05
Maven 프로젝트 나눠서 관리하기  (0) 2019.03.05
Spring Error Page  (0) 2018.08.09
Spring REST API 이미지 또는 파일을 리턴하기  (4) 2018.08.09
댓글
댓글쓰기 폼