<aside> 📖 스프링의 메시지, 국제화 기능
</aside>
메시지 : HTML 파일에 메시지를 하드코딩하지 않고 메시지 관리용 파일을 만들어서 해당 데이터를 key 값으로 불러서 사용하는 것
// message.properties
item=상품
item.id=상품 ID
..
// addForm.html
<label for="itemName" th:text="#{item.itemName}"></label>
// editForm.html
<label for="itemName" th:text="#{item.itemName}"></label>
국제화 : 메시지 파일을 각 나라별로 별도 관리하여 서비스를 국제화하는 것
// message_en.properties
item=Item
..
// message_ko.properties
item=상품
..
accept-language 헤더 값을 사용하거나 언어를 직접 선택/쿠키 등 사용해서 처리 가능MessageSource (인터페이스) 의 구현체인 ResourceBundleMessageSource 를 스프링 빈으로 등록
직접 등록
@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.properties 파일을 기본으로 사용)
파일의 위치는 /resources/messages.properties
여러 파일을 한 번에 지정 가능 : 예시에서는 messages , errors 두 파일 지정
defaultEncoding : 인코딩 정보 지정, utf-8스프링 부트 사용
application.properties 에 메시지 소스 설정 : spring.messages.basename=messages 또는 config.i18n.messagesMessageSource 를 스프링 빈으로 등록하지 않고 별도 설정을 하지 않으면 messages 라는 이름으로 기본 등록 됨 → 해당 파일만 등록하면 자동으로 인식messages.properties : 기본값으로 사용 (한글)messages_en.properties : 영어 국제화 사용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;
}
테스트 코드 작성
@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)
@Test
void notFoundMessageCode() {
Assertions.assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
.isInstanceOf(NoSuchMessageException.class);
}
@Test
void notFoundMessageCodeDefaultMessage() {
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");
}
메시지의 {0} 부분은 매개변수를 전달해서 치환 가능
(hello.name=안녕 {0} → Spring 단어를 매개변수로 전달 → 안녕 Spring)
국제화 파일 선택
@Test
void defaultLang() {
assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
}
ms.getMessage("hello", null, null) : locale 정보 없으므로 Locale.getDefault() 호출하여 기본값 파일인 messages 사용ms.getMessage("hello", null, Locale.KOREA) : locale 정보는 있지만, messages_ko 파일이 없으므로 기본값 파일인 messages 사용@Test
void enLang() {
assertThat(ms.getMessage("hello", null, Locale.ENGLISH))
.isEqualTo("hello");
}
ms.getMessage("hello", null, Locale.ENGLISH) : locale 정보가 ENGLISH 이므로 messages_en 찾아서 사용타임리프 메시지 적용 : #{...} 사용 시 스프링의 메시지를 조회 가능
(ex) <div th:text="#{label.item}"></div> → <div>상품</div>)
타임리프에서 파라미터 사용 : hello.name=안녕 {0} → <p th:text="#{[hello.name](<http://hello.name/>)(${item.itemName})}"></p> → <p>안녕 상품명</p>
웹 브라우저의 언어 설정 값 변경
Accept-Language 값이 변경→ 스프링은 언어 선택 시 기본으로 Accpet-Language 헤더의 값 사용
LocaleResolver : Locale 선택 방식을 변경할 수 있도록 스프링이 제공하는 인터페이스, 기본으로 Accept-Language 활용하는 AcceptHeaderLocaleResolver 사용
public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request
, @Nullable HttpServletResponse response
, @Nullable Locale locale);
}
LocaleResolver 변경 : Locale 선택 방식 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키/세션 기반의 Locale 선택 기능 사용 가능