<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.messages
MessageSource
를 스프링 빈으로 등록하지 않고 별도 설정을 하지 않으면 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 선택 기능 사용 가능