
여러 화면에 보이는 상품명, 가격, 수량 등의 단어를 변경하려면 HTML파일에 하드코딩 되어 있는 여러개의 화면들을 다 찾아가면서 모두 변경해야한다
이러한 문제점을 해결하기 위해 다양한 메시지를 한 곳에 관리하는 기능을 메시지 기능 이라고 한다.
예를 들어 messages.properties라는 메시지 관리용 파일을 만들어서 아래와 같이 작성해준다.
item = 샹품
item.id = 상품 ID
item.itemName = 상품명
item.price = 가격
<label for="itemName" th:text="#{item.itemName}"></label>messages.properties를 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다.item=Item
item.id=Item IDitem.itemName=Item Name
item.price=price
item.quantity=quantity
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
messages_en.properties를 사용하고, 한국어를 사용하는 사람이면 messages_ko.properties를 사용하게 개발하면 된다.그렇다면 한국에서 접근한 것인지 영어권에서 접근한 것인지 인식하는 방법은 뭘까?
accept-language 헤더 값을 사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하면 된다.스프링은 기본적은 메시지와 국제화 기능을 모두 제공하며, 타임리프도 스프링이 제공하는 메시지와 국제화 기능을 편리하게 통합해서 제공한다.
스프링은 기본적인 메시지 관리 기능을 제공한다.
메시지 관리 기능을 사용하려면 스프링이 제공하는 MessageSource를 스프링 빈으로 등록하면 되지만, MessageSource는 인터페이스 이므로 구현체인 ResourceBundleMessageSource를 스프링 빈으로 등록해야한다.
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
messages.properties파일을 읽어서 사용한다.messages_en.properties, messages_ko.properties와 같이 파일명 마지막에 언어 정보를 주면 된다.messages.properties를 기본으로 사용한다.MessageSource를 자동으로 스프링 빈으로 등록한다.spring.messages.basename=messages
MessageSource를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages라는 이름으로 기본 등록 된다.messages_en.properties,messages_ko.properties, messages.properties파일만 등록하면 자동으로 인식된다.
messages.properties: 기본값으로 사용 (한글)
messages_en.propoerties: 영어 국제화 사용
/resources/messages.properties
hello=안녕
hello.name=안녕 {0}
/resources/messages_en.properties
hello=hello
hello.name=hello {0}
@SpringBootTest
public class MessageSourceTest {
@Autowired
MessageSource ms;
@Test
void helloMessage(){
String result = ms.getMessage("hello", null, null);
Assertions.assertThat(result).isEqualTo("안녕");
}
}
ms.getMessage("hello", null,null)code : helloagrs : nulllocale : nullbasename에서 설정한 기본 이름 메시지 파일을 조회한다.basename으로 messages를 지정했으므로 messages.properties파일에서 데이터를 조회한다. @Test
void notFoundMessageCode(){
assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
.isInstanceOf(NoSuchMessageException.class);
}
@Test
void notFounrMessageCodeDefaultMessage(){
String result = ms.getMessage("no_code",null,"기본 메시지", null);
Assertions.assertThat(result).isEqualTo("기본 메시지");
}
NoSuchMessageException예외가 발생한다.defaultMessage)를 사용하면 메시지가 없어도 기본 메시지가 반환된다.@Test
void argumentMessage(){
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
Assertions.assertThat(result).isEqualTo("안녕 Spring");
}
hello.name=안녕 {0} -> 안녕 Spring@Test
void defaultLang(){
Assertions.assertThat(ms.getMessage("hello",null,null)).isEqualTo("안녕");
Assertions.assertThat(ms.getMessage("hello",null, Locale.KOREA)).isEqualTo("안녕");
}
@Test
void enLang(){
Assertions.assertThat(ms.getMessage("hello",null,Locale.ENGLISH)).isEqualTo("hello");
}
ms.getMessage("hello",null,null) : locale정보가 없으므로 messages.사용ms.getMessage("hello",null, Locale.KOREA) : locale 정보가 있지만, message_ko가 없으므로 messages 사용ms.getMessage("hello",null,Locale.ENGLISH) : locale정보가 Locale.ENGLISH이므로 messages_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=취소
button.update=수정
button.add=등록
#{...}를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다.
- 메시지대로 잘 나오는 것을 확인할 수 있다.
#{...}을 통해 메시지를 적용하도록 작성했기 때문에 설정파일만 추가해주면 국제화가 가능하다.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
button.update=Update
button.add=Add