메시지와 국제화 설정

Jaca·2021년 10월 27일
0

기존에 사용하던 상품 등록 폼을 코드로 보자

<form action="item.html" th:action th:object = "${item}" method="post">
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" th:field = "*{itemName}" 
                   class="form-control" placeholder="이름을 입력하세요">
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" th:field = "*{price}" 
                   class="form-control" placeholder="가격을 입력하세요">
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" th:field = "*{quantity}" 
                   class="form-control" placeholder="수량을 입력하세요">
        </div>

당연히 상품명, 가격 등 변수들은 ${item}을 통해 받아와 변수를 통해 뿌려주고 있지만,
라벨에 해당하는 상품명, 가격, 수량이라는 이름은 하드코딩 되어있는 것을 볼 수 있다.

이러한 코딩은 당연히 유연하지 못해 변경에 취약하다.

이것을 유연하게 바꿔보고 언어별 설정까지 살펴보자

MessageSource

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

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

스프링 부트에서 기본 값으로
spring.messages.basename=messages 를 사용하며

MessageSource 를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라는 이름으로 기본 등록된다. 따라서 messages_en.properties , messages_ko.properties , messages.properties 파일만 등록하면 자동으로 인식된다.

이에 따라 메시지 파일을 만든다면,
messages.properties 파일을 기본 값으로 사용하고,
messages_en.properties 처럼 뒤에 언어 설정을 붙여서 국제화에 사용할 수 있다.

MessageSource 인터페이스

messages.properities 파일 예시

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;

getMessage의 파라미터는 아래와 같다.

  • code : messages.properities 에서 가져올 메시지의 키 값이다.
    예를 들어 code에 'hello'를 넣는다면, 파일의 hello를 통해 '안녕'을 찾는다.
  • args : 메시지에 Object 배열의 매개변수를 넘겨줄 수 있다.
    code에 'hello'와 매개변수 배열을 넘겨준다면 0번째 매개 변수를 통해 '안녕' + args의 0번째 매개변수가 더해진다.
  • defaultMessage : 만약 code를 통해 메시지를 찾지 못했을 때 나올 기디폴트 메시지이다. defaultMessage를 설정하지 않았을 때, code가 검색에 실패하면 NoSuchMessageException 이 발생한다.
  • locale : locale 정보를 기반으로 국제화 파일을 선택한다. locale 정보가 없으면 messages 를 사용한다.

타임리프 적용

타임리프의 메시지 표현식 #{...} 를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다.
예를 들어서 방금 등록한 상품이라는 이름을 조회하려면 #{label.item} 이라고 하면 된다.

기존 예시의 하드 코딩된 HTML을 아래와 같이 바꿔주면 된다.

<form action="item.html" th:action th:object="${item}" method="post">
        <div>
            <label for="itemName" th:text="#{label.item.itemName}">상품명</label>
            <input type="text" id="itemName" th:field="*{itemName}" 
                   class="form-control" placeholder="이름을 입력하세요">
        </div>
        <div>
            <label for="price" th:text="#{label.item.price}">가격</label>
            <input type="text" id="price" th:field="*{price}" 
                   class="form-control" placeholder="가격을 입력하세요">
        </div>
        <div>
            <label for="quantity" th:text="#{label.item.quantity}">수량</label>
            <input type="text" id="quantity" th:field="*{quantity}" 
                   class="form-control" placeholder="수량을 입력하세요">
        </div>

국제화 설정

Accept-Language 의 값을 통해 언어를 설정하게 되는데,
Accept-Language 는 클라이언트가 서버에 기대하는 언어 정보를 담아서 요청하는 HTTP 요청 헤더이다.

사실 이미 타임리프로 HTML 파일 설정을 맞췄기 때문에,
messages_en.properties 파일만 만들고 헤더값을 조정해주면
렌더링이 잘 되는 것을 확인할 수 있다.

스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데,
스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.

만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다.
예를 들어서 고객이 직접 Locale 을 선택하도록 하는 것이다.
관련해서 LocaleResolver 를 검색하면 수 많은 예제가 나온다니 필요할 때 도전해보자

profile
I am me

0개의 댓글