ApplicationContext인터페이스는MessageSource라는 인터페이스를 상속하므로 국제화 기능을 제공합니다. 이 인터페이스는 스프링이 메세지를 가져오는 기반을 제공합니다.
-
하드 코딩된 문자열을 사용하는 것보다 문자열들을 별도의 파일로 관리하는 것이 유지 보수에 좋다 이때
MessageSource를 사용한다.- 수정이 필요한 경우 하드 코딩된 문자열을 모두 찾아 고쳐야한다
- 별도의 파일로 관리할 경우 해당 파일에서 문자열을 한 번만 수정하면 해당 문자열을 사용하는 모든 곳이 업데이트된다.
-
메시지 파일을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다.
- 메시지 관리 기능을 사용하려면 스프링이 제공하는
MessageSource를 스프링 빈으로 등록하면 된다. MessageSource는 인터페이스이다. 따라서 구현체인ResourceBundleMessageSource를 스프링 빈으로 등록하면 된다
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;
}@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}-
basenames: 설정 파일의 이름을 지정한다.messages로 지정하면messages.properties파일을 읽어서 사용한다.
-
국제화 기능을 적용하려면
basenames뒤에 언어 정보를 표시한다.- 예시)
messages_en.properties,messages_ko.properties - 만약 찾을 수 있는 국제화 파일이 없으면
messages.properties(언어정보가 없는 파일명)를 기본으로 사용한다.
- 예시)
-
파일의 위치는
/resources/messages.properties이다 -
여러 파일을 한번에 지정할 수 있다.
- 여기서는
messages,errors둘을 지정했다.
- 여기서는
-
defaultEncoding: 인코딩 정보를 지정한다. utf-8 을 사용하면 된다.
- 스프링 부트를 사용하면 스프링 부트가 MessageSource 를 자동으로 스프링 빈으로 등록한다.
- 스프링 부트에서는 아래와 같이 메세지 소스를 설정할 수 있다.
application.properties
/resources/config/i18n/messages.properties를 메시지 파일로 사용한다.
spring.messages.basename=config.i18n.messages
spring.messages.encoding=utf-8스프링 부트 메시지 소스 기본 값
MessageSource를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면messages라는 이름으로 기본 등록된다.- 따라서
messages_en.properties,messages_ko.properties,messages.properties파일을/resources디렉토리에 만들면 자동으로 인식된다.
/resources디렉토리에messages.properties와messages_en.properties를 작성
messages.properties
hello=안녕
hello.name=안녕 {0}messages_en.properties
hello=hello
hello.name=hello {0}- 스프링 부트를 사용하면 스프링 부트가 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;
}String getMessage(String code, Object[] args, String default, Locale loc)
MessageSource에서 메시지를 검색하는 데 사용되는 기본 방법이다.- 지정된 로케일에 대한 메시지를 찾을 수 없는 경우
defaultMessage가 사용된다. - 전달된
args는 표준 라이브러리에서 제공하는MessageFormat기능을 사용하여 메세지의 값을 대체한다.
String getMessage(String code, Object[] args, Locale loc)
- 본질적으로 이전 방법과 동일하지만 다음과 한 가지 차이점이 있다.
defaultMessage를 지정하지 않았기 때문에 메시지를 찾을 수 없는 경우NoSuchMessage예외를 던진다.
@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);
}- 메시지가 없는 경우에는
NoSuchMessageException이 발생한다.
@Test
void notFoundMessageCodeDefaultMessage() {
String result = ms.getMessage("no_code", null, "기본 메시지", null);
assertThat(result).isEqualTo("기본 메시지");
}- 메시지가 없으면 기본 메시지(
defaultMessage)를 사용한다.
@Test
void argumentMessage() {
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(result).isEqualTo("안녕 Spring");
} - 메시지의 {0} 부분은 매개변수를 전달해서 치환할 수 있다
locale정보를 기반으로 국제화 파일을 선택한다.- 한국에서 접근한 것인지 영어에서 접근한 것인지는 인식하는 방법은 HTTP
accept-language해더 값을 사용한다. Accept-Language는 클라이언트가 서버에 기대하는 언어 정보를 담아서 요청하는 HTTP 요청 헤더이다.Locale이 en_US 의 경우messages_en_USmessages_enmessages순서로 찾는다.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정보가 없으므로messages를 사용한다ms.getMessage("hello", null, Locale.KOREA): locale 정보가 있지만,message_ko가 없으므로messages를 사용한다
@Test
void enLang() {
assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}ms.getMessage("hello", null, Locale.ENGLISH):locale정보가Locale.ENGLISH이므로messages_en을 찾아서 사용한다
- 타임리프의 메시지 표현식 #{...} 를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다.
메세지 파일
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=취소타임리프 메시지 적용
렌더링 전
<div th:text="#{label.item}"></h2>
렌더링 후
<div>상품</h2>
참고