오늘 김영한님의 스프링 mvc2를 들으며 메세지와 국제화에 대해서 배웠다.
이 둘을 간단히 설명하면 하드코딩된 부분을 html파일마다 고치기 번거로워서
이걸 한번에 고칠 수 있는 메세지라는 기능이 있다는 것!
그리고 마찬가지로 국제화는 이 메세지라는 기능을 언어적으로 접근하는 것이다.
내가 지금 한국에 있으면 한국어 메세지를
미국에 있으면 미국어 메세지를 선택하도록 하는 기능이다.
사용자가 미국에 있으면 영어로
한국에 있으면 한국어로 하는 것이다.
이 둘을 좀 더 자세히 배워보자
오늘도 Ready, Set, Go! 🏃🏃♂️🏃♀️
<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>
...
위와 같이 상품명이라고 못박아 둔 곳이 있다.
이렇게 "상품명"이라고 못박아 둔 곳을 "상품이름"이라고 바꾸고자 할 때 개발자는
모든 html파일에 들어가 "상품명"을 "상품이름"으로 바꿔야한다.
이는 너무너무 번거롭다.
이를 편하게 하는 스프링의 기능이 존재한다.
MessageSource라는 인터페이스를 스프링 빈으로 등록하는 것!
하지만 MessageSource는 인터페이스이므로 이를 구현한 ResourceBundleMessageSource를 스프링 빈으로 등록
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
setBasenames()을 통해서 설정 파일의 이름을 지정한다.
위 예시 "messages"는 messages.properties의 값들을 참고하겠다는 이야기이다.
만약에 국제화 기능을 사용하려고 한다면 messages 뒤에 _en 즉 messages_en으로 언더바 언어정보를 주면 된다. -> 그러나 이 파일이 없는 경우 기본 설정 파일인 messages.properties를 참조한다.
파일 위치는 resources 안에 둔다.
스프링 부트는 위와 같이 직접 등록하지 않아도 자동으로 스프링 빈을 등록해준다.
그 대신 application.properties에 메세지 소스를 설정해줘야 한다.
spring.messages.basename=messages,config.i18n.messages
단, spring.messages.basename=messages
이건 기본값이므로 생략 가능하다. 왜냐하면 기본으로 messages라는 이름으로 등록되기 때문이다. 국제화를 이용하려면 그냥 추가적으로 _언어의 properties 파일을 생성하면 자동으로 이 또한 등록한다.
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;
Test할 때 MessageSource 인터페이스의 getMessage()메서드를 통해서 messages.properties에 저장된 메세지 정보, argument, locale 정보 값을 넣어 가져온다.
@Test
void helloMessage() {
String result = ms.getMessage("hello", null, null);
assertThat(result).isEqualTo("안녕");
}
argument와 local 정보가 null이므로 기본 messages.properties에서 가져온다.
@Test
void notFoundMessageCode() {
assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
.isInstanceOf(NoSuchMessageException.class);
}
해당 메세지가 없는 경우 NoSuchMessageException이라는 예외를 던짐
@Test
void notFoundMessageCodeDefaultMessage() {
String result = ms.getMessage("no_code", null, "기본 메시지", null);
assertThat(result).isEqualTo("기본 메시지");
}
없는 경우 default값 설정이 가능하다.
@Test
void argumentMessage() {
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(result).isEqualTo("안녕 Spring");
}
앞서 저장된 hello.name= 안녕 {0}
이 부분에 {0}이라는 argument가 존재하여 저 곳에 "Spring"이라는 단어를 넣는 것이다.
@Test
void defaultLang() {
assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
}
Lacale.KOREA라고 선택했지만 messages_ko.properties 정보가 없기 때문에 기본 설정 정보인 messages.properties의 내용을 가져간다.
@Test
void enLang() {
assertThat(ms.getMessage("hello", null,Locale.ENGLISH)).isEqualTo("hello");
}
Locale.ENGLISH이므로 messages_en.properties 설정 정보를 찾아 국제화
사실 이 부분부터는 너무 간단하다 하드코딩된 부분에
th:test="#{item.item}"
이라고 넣어주는 것이다.
messages.properties
item.item="상품"
messages_en.properties
item.item="product"
그러면 저렇게 설정된 모든 화면이 한국이라면 "상품"으로 영어권이면 "product"로 나온다.