Spring

메시지와 국제화

potatoo 2023. 7. 3. 17:08
728x90

여러 화면에 보이는 상품명, 가격, 수량 등, label에 있는 단어를 변경하려면 다음 화면들을 다 찾아가면서 모두 변경해야 한다. 화면 수가 적으면 문제가 되지 않지만 화면이 수십개 이상이라면 수십개의 파일을 모두 고쳐야 한다.

 

이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다.

예를 들어서 messages.properties 라는 메시지 관리용 파일을 만들고

item=상품 item.id=상품 ID item.itemName=상품명 item.price=가격 item.quantity=수량

 

HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용하는 것이다.

<label for="itemName" th:text="#{item.itemName}"></label>

 

이러한 메시지 관리를 한 발 더 나가서 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다. 

 예를 들어 영어권과 한국으로 나누어서 메시지를 관리할 수 있다.

messages_en.properties
 	item=Item
  	item.id=Item ID
    	item.itemName=Item Name
  	item.price=price
	item.quantity=quantity
 
messages_ko.properties
item=상품 
item.id=상품 ID 
item.itemName=상품명 
item.price=가격 
item.quantity=수량

한국에서 접근한 것인지 영어에서 접근한 것인지는 인식하는 방법은 HTTP accept-language 해더 값을

사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하면 된다.

 스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다. 그리고 타임리프도 스프링이 제공하는 메시지와 국제화 기능을 편리하게 통합해서 제공한다.

메시지 관리 기능을 사용하려면 제공하는 MessageSource를 스프링 빈으로 등록하면 되는데, MessageSource는 인터페이스이다. 따라서 구현체인 ResourceBundleMessageSource를 스프링 빈으로 등록하면 된다.

 

직접 등록하는 방법은 설정 파일의 이름을 지정하고, 인코딩 정보를 지정하여 사용하면 된다.

@Bean
public MessageSource messageSource(){
	ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
	messageSource.setBasenames("messages","errors");
	messageSource.setDefaultEncoding("utf-8");
    	return messageSource;

basenames : 설정 파일의 이름을 지정한다.
messages 로 지정하면 messages.properties 파일을 읽어서 사용한다.

추가로 국제화 기능을 적용하려면 messages_en.properties , messages_ko.properties 와 같이 파일명 마지막에 언어 정보를 주면된다.

만약 찾을 수 있는 국제화 파일이 없으면 messages.properties (언어정보가 없는 파일명)를 기본으로 사용한다.

파일의 위치는 /resources/messages.properties 에 두면 된다.

여러 파일을 한번에 지정할 수 있다. 여기서는 messages , errors 둘을 지정했다.

defaultEncoding : 인코딩 정보를 지정한다. utf-8 을 사용하면 된다.

 

스프링 부트를 사용하면 메시지 소스를 아래와 같이 설정할 수 있다.

application.properties에

spring.messages.basename=messages,config.i18n.messages

 

스프링 부트 메시지 소스 기본 값

spring.messages.basename=messages

MessageSource 를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라는 이름으로 기본 등록된다.

따라서 messages_en.properties , messages_ko.properties , messages.properties 파일만 등록하면 자동으로 인식된다.

메시지 파일을 만들어 보면,

messages.properties:기본 값으로 사용(한글) /resources/messages.properties

hello = 안녕
hello.name = 안녕{0}

messages_en.properties:영어 국제화 사용 /resources/messages_en.properties

hello=hello
hello.name = hello{0}

위의 메시지 properties를 테스트하는 과정에서 한글 인코딩 문제가 발생할 수 있는데 이 경우에는 IDE에서 encoding setting을 utf-8로 바꿔주면 해결된다.

테스트 코드는 아래와 같다.

@Autowired
MessageSource ms;

@Test
public void helloMessage(){
    	String result = ms.getMessage("hello", null, Locale.KOREA);
    	Assertions.assertThat(result).isEqualTo("안녕");
}

가장 단순한 테스트는 메시지 코드로 hello 를 입력하고 나머지 값은 null 을 입력했다.
locale 정보가 없으면 basename 에서 설정한 기본 이름 메시지 파일을 조회한다.

basename 으로 messages 를 지정 했으므로 messages.properties 파일에서 데이터 조회한다.

 

그 다음은 메시지가 비어있는 경우를 테스트 해본다.

@Test
void notFoundMessageCode(){
        assertThatThrownBy(()->ms.getMessage("no_code",null,null))
                .isInstanceOf(NoSuchMessageException.class);
}

위의 코드는 메시지가 비어있어서 예외가 터지는 지 확인하는 테스트이다.

더보기

- assertThatThrownBy 사용법

 

익셉션이 발생하는 케이스를 테스트할 때 사용합니다.

  • 파라미터: 익셉션이 발생하는 메서드를 람다식으로 입력
  • 체이닝
    • isInstanceOf: 예상되는 익셉션을 .class 형태로 입력
    • hasMessageContaining: 익셉션 메시지에 입력되는 문자열이 포함되는지 확인
@Test
void notFoundMessageCodeDefaultMessage(){
        String result = ms.getMessage("no_code", null, "기본 메시지", null);
        assertThat(result).isEqualTo("기본 메시지");
}

위의 코드는 메시지가 비어있으면 기본적으로 보낼 defalut메시지를 설정하는 테스트이다.

       

@Test
void argumentMessage(){
        String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        assertThat(result).isEqualTo("안녕 Spring");
}

이번에는 properties에 등록한 배열 매개변수 전달 방법이다. 객체 배열에 있는 Spring이 properties에 정의한 메시지의 안녕 뒤에 {0} 부분에 들어간다.

@Test
void defaultLang(){
        assertThat(ms.getMessage("hello",null,null)).isEqualTo("안녕");
        assertThat(ms.getMessage("hello",null,Locale.KOREA)).isEqualTo("안녕");
}

@Test
void enLang(){
        assertThat(ms.getMessage("hello",null,Locale.ENGLISH)).isEqualTo("hello");
}

그 다음은 국제화 테스트이다. 기본값인 한국어와 따로 정의한 영어 메시지를 테스트한다.

 

728x90