mvc 2
안에서 message-start
폴더에 있는 프로젝트를 활용한다.
메시지와 국제화만을 다루기 위해서 이전에 다뤘던 설렉트 박스, 라디오 박스 없는 버전으로 사용한다.
여러 화면에서 보이는 상품명, 가격, 수량 등, label
에 있는 단어를 변경하려면 다음 화면들을 다 찾아가면서 모두 변경해야 한다.
작은 프로젝트일 경우에는 직접 찾아서 수기로 고치면 되지만, 프로젝트가 점점 커지면 일일이 고치는 것은 점점 골치아파질 것이다.
이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다.
예를 들어서 messages.properties
라는 메시지 관리용 파일을 만들고
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
각 HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용하는 것이다.
<label for="itemName" th:text="#{item.itemName}"></label>
국제화란 쉽게 말해 메시지를 여러 언어로 하고싶다는 느낌이다.
message_en.properties
item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity
message_ko.properties
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
영어를 사용하는 사람이면 message_en.properties
를 사용하고
한국이면 message_ko.properties
를 사용하게 개발하면 된다.
한국에서 접근한 것인지 영어에서 접근한 것인지 알 수 있는 방법중에 대표적인 방법은 HTTP accept-language
헤더 값을 사용하는 방법이다.
그 외에는 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하는 방법이 있다.
스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다.
타임리프도 스프링이 지원하는 기능을 편리하게 사용할 수 있도록 제공해준다.
스프링은 기본적인 메시지 관리 기능을 제공한다.
메시지 관리 기능을 사용하려면 MessageSource
를 스프링 빈으로 등록하면 되는데, MessageSource
는 인터페이스이다. 그러므로 구현체인 ResourceBundleMessageSource
를 스프링 빈으로 등록하면 된다.
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
basename
: 설정 파일의 이름을 지정한다.
messages
로 지정하면 messages.properties
파일을 읽어서 사용한다.
추가로 국제화 기능을 적용하려면 messages_en.properties
, messages_ko.properties
와 같이 파일명 마지막에 언어 정보를 주면 된다. 만약 찾을 수 있는 국제화 파일이 없으면 messages.properties
를 기본으로 사용한다.
파일 위치는 /resources/messages.properties
여러 파일 지정가능하다. messages
, errors
둘을 지정했다.
스프링 부트를 사용하면 MessageSource
를 자동으로 스프링 빈으로 등록한다.
application.properties
spring.messages.basename=messages,config.i18n.messages
스프링 부트 메시지 소스 기본 값
spring.messages.basename=messages
아무것도 설정안하면 messages
라는 이름으로 기본 등록된다. 그러므로 message_en.properties
, message_ko.properties
, message.properties
파일만 등록하면 자동으로 인식된다.
혹시 옵션을 추가로 알고 싶다면,
여기서 검색하여 찾아볼 수 있다.
기본값이 한글로 되어있으므로 영어가 아닌 다른 지역은 기본값인 한글로 보게 된다.
package hello.itemservice.message;
import org.assertj.core.api.Assertions;
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 org.springframework.context.NoSuchMessageException;
import java.util.Locale;
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("안녕");
}
@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 message = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(message).isEqualTo("안녕 Spring");
}
@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");
}
}
타임리프에서 메시지를 적용하려면
#{...}
라고 하면 된다.
렌더링 전
<div th:text="#{label.item}"></h2>
렌더링 후
<div>상품</h2>
이런 식으로 바꿔주면 된다.
파라미터는 다음과 같이 사용할 수 있다.
hello.name=안녕 {0}
<p th:text="#{hello.name(${item.itemName})}"></p>
이제 웹 어플리케이션에 영어를 적용시켜보자.
끝났다.
#{...}
를 넣으면 그 값은 한국어도 있고 영어도 있는 것을 확인할 수 있다. 그러므로 우리가 해야할 일은 언어에 따라 바꿔지도록 설정해주면 되는데 이마저 스프링이 자동으로 해준다.
테스트를 위해 크롬 설정에서 언어를 가장 위로 설정해주고 실행하면
이렇게 영어로 바뀐것을 확인할 수 있다. 레전드
웹 브라우저 언어 설정 값을 변경하면 요청시 Accept-Language
의 값이 변경되므로 그에 따라 바뀌게 된 것이다.
테스트에 있듯이 메시지 기능은 Locale
정보를 알아야 언어를 선택할 수 있다.
결국 스프링도 Locale
정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 Accept-Language
헤더의 값을 사용한다.
LocaleResolver
스프링은 Locale
선택 방식을 변경할 수 있도록 LocaleResolver
라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language
를 활용하는 AcceptHeaderLocaleResolver
를 사용한다.
public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request, @Nullable HttpServletResponse
response, @Nullable Locale locale);
}
국제화의 경우 어... 필요할때 사용하면 된다.