메시지, 국제화
메시지, 국제화 소개
메시지
- 다양한 메시지를 아래와 같이 하나의 파일에서 관리할 수 있음
messages.properties
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
addForm.html
:<label for="itemName" th:text="#{item.itemName}"></label>
editForm.html
:<label for="itemName" th:text="#{item.itemName}"></label>
국제화
- 사용자 언어에 따라 다른 메시지를 제공할 수 있음
messages_en.properties
item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity
messages_ko.properties
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
스프링 메시지 소스 설정
직접 등록
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new
ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
basenames
: 설정 파일의 이름을 지정messages
로 지정하면messages.properties
파일을 사용- 추가로 국제화 기능을 적용하려면
messages_en.properties
,messages_ko.properties
와 같이 파일명 마지막에 언어 정보를 줌. 만약 찾을 수 있는 국제화 파일이 없으면messages.properties
(언어정보가 없는 파일명)를 기본으로 사용 - 파일의 위치는
/resources/messages.properties
- 여러 파일을 한번에 지정할 수 있음
defaultEncoding
: 인코딩 정보를 지정한다.utf-8
을 사용
스프링 부트
- 스프링 부트를 사용하면 스프링 부트가
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.properties
hello=안녕 hello.name=안녕 {0}
스프링 메시지 소스 사용
package hello.itemservice.message;
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 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("안녕");
}
}
ms.getMessage("hello", null, null)
code
:hello
args
: `nulllocale
:null
locale
정보가 없으면basename
에서 설정한 기본 이름 메시지 파일을 조회basename
으로messages
를 지정 했으므로messages.properties
파일을 조회
MessageSourceTest 추가 - 메시지가 없는 경우, 기본 메시지
@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("기본 메시지");
}
- 메시지가 없는 경우에는
NoSuchMessageException
- 메시지가 없어도 기본 메시지(
defaultMessage
)를 사용하면 기본 메시지가 반환
MessageSourceTest 추가 - 매개변수 사용
@Test
void argumentMessage() {
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(result).isEqualTo("안녕 Spring");
}
- 다음 메시지의 {0} 부분은 매개변수를 전달해서 치환
hello.name=안녕 {0}
→ Spring 단어를 매개변수로 전달 →안녕 Spring
국제화 파일 선택
- locale 정보를 기반으로 국제화 파일을 선택, 구체적인 것 우선
- Locale이 en_US 의 경우
messages_en_US
→messages_en
→messages
순서
MessageSourceTest 추가 - 국제화 파일 선택1
@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
를 사용
MessageSourceTest 추가 - 국제화 파일 선택2
@Test
void enLang() {
assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}
ms.getMessage("hello", null, Locale.ENGLISH)
:locale
정보가Locale.ENGLISH
이므로messages_en
을 찾아서 사용
웹 애플리케이션에 메시지 적용하기
- 타임리프 메시지 표현식:
#{...}
- 파라미터 사용
hello.name=안녕 {0}
<p th:text="#{hello.name(${item.itemName})}"></p>
웹 애플리케이션에 국제화 적용하기
스프링의 국제화 메시지 선택
- 스프링은 언어 선택시 기본으로
Accept-Language
헤더의 값을 사용
LocaleResolver
- 스프링은
Locale
선택 방식을 변경할 수 있도록LocaleResolver
라는 인터페이스를 제공 - 스프링 부트는 기본으로
Accept-Language
를 활용하는AcceptHeaderLocaleResolver
를 사용한다