제육's 휘발성 코딩
반응형

메시지, 국제화

메시지 : 여러 화면에서 동일한 명칭으로 하드 코딩되어 있는 것을 한 곳에서 관리하는 기능을 의미한다. 예를 들어 messages.properties라는 메시지 관리용 파일을 만들고 각 HTML은 해당 데이터를 key 값으로 불러서 사용하는 것이다.

다음 예시를 살펴 보자.

item = 상품
item.id = 상품 ID
item.itemName = 상품명
item.price = 가격
item.quantity = 수량
  • messages.properties라는 메시지 관리용 파일
<label for="itemName" th:text="#{item.itemName}"></label>
  • 해당 label을 각 HTML에서 렌더링하여 사용한다.

국제화 : 메시지에서 설정한 파일을 각 나라별로 관리하여 서비스를 제공하는 것을 국제화라고 한다. 예를 들어 message_en.propertiesmessage_ko.properties를 사용하여 국제화를 적용시킬 수 있다.

나라 별 접근 확인은 HTTP의 accept-language를 사용하거나, 사용자가 직접 언어를 선택하도록 하고 쿠키 등을 사용해서 처리할 수 있다.

스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다. 또한, 타임리프도 스프링이 제공하는 국제화 기능을 편리하게 통합해서 제공한다. 지금부터 스프링이 제공하는 메시지와 국제화 기능을 알아보자.

스프링 메시지 소스 설정

image

  • 스프링은 기본적인 메시지 관리 기능을 제공한다. 메시지 관리 기능을 사용하려면 MessageSource를 스프링 빈으로 등록하면 되는데 인터페이스로 만들어져 있다. 즉, 구현체인 ResourceBundleMessageSource를 스프링 빈으로 등록하면 된다.
  • 스프링 부트는 MessageSource를 자동으로 스프링 빈으로 등록해준다. 별도의 설정을 하지 않아도 messages라는 이이름으로 spring.messages.basename=messages가 기본적으로 등록되어 있으며 resources 디렉토리 바로 밑에 messages_en.properties, messages_ko.properties 등 파일만 등록하면 자동으로 인식된다.
  • 스프링 부트에서 MessageSource를 추가로 사용하려면 application.propertiesspring.messages.basename=messages,config.i18n.messages 와 같이 경로를 넣어주면 된다.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.MessageSource;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

    @Test
    void helloMessage() {
        String result = ms.getMessage("hello", null, null);
        assertThat(result).isEqualTo("안녕");
    }
}
  • 테스트 코드를 통해 메시지 코드를 확인해 보자. locale정보가 없으면 기본 파일인 messages.properties를 조회한다.
@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 result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
  assertThat(result).isEqualTo("안녕 Spring");
}
  • 메시지가 없는 경우 NoSuchMessageException이 발생한다.
  • 메시지가 없어도 세번째 파라미터인 defaultMessage를 사용하면 기본 메시지가 반환된다.
  • {0}부분은 매개변수를 전달해서 치환할 수 있다. 단, ms.getMessage에서 오브젝트 배열로 반환해줘야 한다.
@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");
}
  • 국제화 테스트 : Locale.국가를 통해 확인할 수 있다. Locale.ENGLISHmessages_en을 찾아서 사용

웹 애플리케이션에 메시지 적용하기

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

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

page.items=상품 목록
page.item=상품 상세
page.addItem=상품 등록
page.updateItem=상품 수정

button.save=저장
button.cancel=취소
  • message.properties에 메시지를 추가하자.
<div th:text="#{label.item}"></div>
<div>상품</div>
  • 타임리프의 메시지 표현식인 #{...}를 사용하면 스프링 메시지를 편리하게 조회할 수 있다.

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

image

hello=hello
hello.name=hello {0}

label.item=Item
label.item.id=Item ID
label.item.itemName=Item Name
label.item.price=price
label.item.quantity=quantity

page.items=Item List
page.item=Item Detail
page.addItem=Item Add
page.updateItem=Item Update

button.save=Save
button.cancel=Cancel
  • 기존의 HTML에 메시지 적용을 하면서 #{...} 처리를 해두었기 때문에 국제화 작업은 거의 끝났다.

image

  • 크롬 브라우저에서 설정 - 언어 - 영어를 상단으로 올리고 새로고침하면 en으로 렌더링 되는 것을 볼 수 있다.

image

  • Request Headers를 보면 허용 언어의 우선 순위가 지정되어 있음을 볼 수 있다. 즉, 방금 했던 크롬에서의 언어 설정은 해당 언어의 우선 순위를 바꾸는 것과 동일하다.

LocaleResolver

public interface LocaleResolver {
    Locale resolveLocale(HttpServletRequest request);
    void setLocale(HttpServletRequest request, @Nullable HttpServletResponse
  response, @Nullable Locale locale);
}
  • 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language를 활용하는 AcceptHeaderLocaleResolver를 사용한다.
  • Locale 선택 방식을 변경하려면 해당 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다. 예를 들면 고객이 직접 Locale을 선택하도록 하는 것이다.

본 포스팅은 인프런 - 김영한님의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 참고하였습니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^