(스프링 mvc 2) 메시지, 국제화 소개

짜스의 하루 ·2024년 3월 11일

메시지, 국제화 소개

메시지

여러 화면에 보이는 상품명, 가격, 수량 등, label에 있는 단어를 변경하려면, 다 찾아가면서 변경을 해야 한다.
--> 이러한 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라고 한다.
예를 들어, message.properties라는 메시지 관리용 파일을 만들고,
값을 넣어서, 데이터를 키값으로 불러서 사용하는 것이다.

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

국제화

메시지에서 설명한 메시지 파일 (messages.properties)을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다.
예를 들어서 다음과 같이 2개의 파일을 만들어서 분류한다.

messages_en.properties

messages_ko.properties

영어를 사용하는 사람이면 messages_en.properties 를 사용하고, 한국어를 사용하는 사람이면 messages_ko.properties 를 사용하게 개발하면 된다.
--> 직접 구현할 수 있지만, 스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다


스프링 메시지 소스 설정

스프링은 기본적인 메시지 관리 기능을 제공해준다

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

  • messageSource.setBasenames("messages","errors")
    --> messages로 지정하면, resourse 경로에 있는 messages.properties라는 파일의 경로를 읽어서 사용한다. (위 예시는 "errors"도 넣었으니, errors.properties 도 읽어들인다.)
  • 추가로 국제화 기능을 적용하려면 messages_en.properties , messages_ko.properties 와 같이 파일명 마지막에 언어 정보를 주면된다. 만약 찾을 수 있는 국제화 파일이 없으면 messages.properties (언어정보가 없는 파일명)를 기본으로 사용한다. (-> 뒷부분 국제화에서 상세설명)
  • /resources/messages.properties 에 두면 되고, 여러 파일을 한 번에 지정할 수 있다.

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

스프링 부트 메시지 소스 설정--> application.properties
spring.messages.basename=messages,config.i18n.messages라고 등록할 수 있다.

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

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

메시지 파일 만들기
국제화 테스트를 위해서 messages_en 파일도 만들어봤다.

참고

  • messages.properties : 기본값으로 사용(한글)
  • messages_en.propertise : 영어 국제화 사용
    (주의) 파일명은 massage가 아니라 messages이다. 마지막 s에 주의하자. ( /resources/messages.properties )

파일 생성

/resources/messages.properties

/resources/messages_en.properties!


스프링 메시지 소스 사용

MessageSource 인터페이스

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

단순한 테스트 - helloMessage()

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

    @Test
    void helloMessage(){
        String result = ms.getMessage("hello", null, null);
        assertThat(result).isEqualTo("안녕");
    }
  • ms.getMessage("hello",null,null)
    --> code : hello, args: null, locale: null

매시지가 없는 경우, 기본 메시지

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

    @Test
    void notFoundMessageCode(){
        String result = ms.getMessage("no_code", null, "기본 메시지", null);
        assertThat(result).isEqualTo("기본 메시지");
    }
  • (코드에 해당하는) 메시지가 없는 경우에는 NoSuchMessageException 이 발생한다.
  • (코드에 해당하는) 메시지가 없어도 기본 메시지( defaultMessage )를 사용하면 기본 메시지가 반환된다.

매개변수 사용

@Test
    void argumentMessage(){
        String message = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        assertThat(message).isEqualTo("안녕 Spring");
    }
  • 메시지의 {0} 부분은 매개변수를 전달해서 치환할 수 있다. (값을 넘길 때에는 Object 배열을 넘겨야 한다)
  • hello.message = 안녕{0} -> 'Spring'이라는 단어를 매개변수로 전달 -> 안녕 Spring

국제화 파일 선택

  • Locale이 en_US의 경우, messages_en_US -> messages_en -> messages 순서로 찾는다.
  • Locale에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고, 없으면 디폴트를 찾는다고 이해하면 된다.
 @Test
    void defaultLang(){
        assertThat(ms.getMessage("hello",null,null)).isEqualTo("안녕");
        assertThat(ms.getMessage("hello",null, Locale.KOREA)).isEqualTo("안녕");
    }
  • ms.getMessage("hello", null, null) : locale 정보가 없으므로 message를 사용
  • ms.getMessage("hello", null, Locale.KOREA) : locale 정보가 있지만, messages.ko가 없으므로 messages를 사용

국제화 파일 선택 2

 @Test
    void enLang(){
        assertThat(ms.getMessage("hello",null,Locale.ENGLISH)).isEqualTo("hello");
    }
  • ms.getMessage("hello", null, Locale.ENGLISH) : locale 정보가 Locale.ENGLISH 이므로 messages_en 을 찾아서 사용.

(참고)
Locale 정보가 없는 경우 Locale.getDefault() 을 호출해서 시스템의 기본 로케일을 사용한다.
예) locale = null 인 경우 시스템 기본 locale 이 ko_KR 이므로 messages_ko.properties 조회 시도 -> 조회 실패 -> messages.properties 조회


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

메시지에 먼저 추가해보자

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

상품이라는 이름을 조회하려면, #{label.item}이라고 하면 된다.

렌더링 전
<div th:text="#{label.item}"></div>

렌더링 후
<div>상품</div>

addForm.html

이런식으로 나머지 editForm.html, item.html, items.html 에 적용하면 된다.


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

영어 메시지 추가

사실 이것으로 국제화 작업은 거의 끝났다. 앞에서 이미 템플릿 파일에 모두 #{...} 를 통해서 메시지를 사용하도록 적용해두었기 때문이다.

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

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

LocalResolver

  • 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.
  • (참고) LocaleResolver 변경
    만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다.
    ---> 예를 들어서, 고객이 직접 Locale 을 선택하도록 하는 것이다. 관련해서 LocaleResolver 를 검색하면 수 많은 예제가 나오니 필요한 경우 참고하자.
profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글