Spring

[Spring]메세지, 국제화 사용해보기

마닐라 2022. 6. 6. 19:02

메세지

메세지는 하드코딩되어 있는 메세지들을 한 곳에서 관리하도록 관리 하는 기능을 한다.

수십페이지에서 동일한 메세지를 사용하고 있고 그 부분에 변경사항이 일어나면 일일이 변경해줘야하는 번거로움을 줄이고자 메세지로 따로 관리하는 것이 좋다.

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

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

 

각 HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용할 수 있다.

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

 

국제화

메세지에서 한 발 더 나아가서 메세지 파일을 각 나라별로 별도로 관리하면 서비스를 국제화할 수 있다.

예를 들어서 다음과 같이 2개의 파일을 만들어서 분류한다.

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 , errors 둘을 지정했다.

 

스프링 부트를 사용하면 스프링 부트가 MessageSource 를 자동으로 스프링 빈으로 등록한다.

다음과 같이 메시지 소스를 설정할 수 있다.

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

.

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

spring.messages.basename=messages

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

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

 

MessageSource 인터페이스를 보면 코드를 포함한 일부 파라미터로 메세지를 읽어오는 기능을 제공한다.

public interface MessageSource {
    String getMessage(String code, @Nullable Object[] args, @Nullable String
            defaultMessage, Locale locale);
    String getMessage(String code, @Nullable Object[] args, Locale locale) throws
            NoSuchMessageException;

 

 

스프링이 제공하는 메시지 소스를 어떻게 사용하는지 테스트 코드를 통해서 학습해보자.

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

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

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

    @Test
    void notFoundMessageCodeDefaultMessage() {
        String result = ms.getMessage("no_code", null, "기본 메시지", null);
        assertThat(result).isEqualTo("기본 메시지");
    }

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

    @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");
    }
}

 

테스트 별로 결과를 정리해봤다.

1. hello라는 메세지의 값을 출력한다.

2. 위와 같은데 메세지가 없을 땐 NoSuchMessageException이 발생한다.

3. 위와 같은데 defaultMessage를 사용하면 메세지가 없을 때 기본 메세지를 사욯안다.

4. 매개변수로 Object 배열을 전달하고 해당 부분은 치환할 수 있다.

hello.name=안녕 {0} --> 안녕 Spring

5,6.locale 정보를 기반으로 국제화 파일을 선택한다.

locale이 en_US의 경우 messages_en_US -> messages_en -> messages 순서로 찾는다.

locale에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고 없으면 디폴트를 찾는다.

 

타임리프 메시지 적용

타임리프의 메세지 표현식 #{...}를 사용하면 스프링의 메세지를 편리하게 조회할 수 있다.

 

렌더링 전

<div th:text="#{label.item}"></h2>

렌더링 후

<div>상품</h2>

 

참고로 파라미터는 다음과 같이 사용할 수 있다.

hello.name=안녕 {0}
<p th:text="#{hello.name(${item.itemName})}"></p>

 

웹 애플리케이션에 국제화 적용하기

앞서 MessageSource 테스트에서 보았듯이 메시지 기능은 Locale 정보를 알아야 언어를 선택할 수 있다.

결국 스프링도 Locale 정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 Accept-Language 헤더의 값을 사용한다.

 

LocaleResolver

스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데,

스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.

 

LocaleResolver 변경

만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다.

예를 들어서 고객이 직접 Locale 을 선택하도록 하는 것이다.

관련해서 LocaleResolver를 검색하면 수 많은 예제가 나오니 필요하면 참고하자.

 

출처

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/