: '상품목록', '상품명' 등과 같은 레이블을 바꾸고 싶다면, 각 html에 하나하나 들어가서 텍스트를 수정하는 방법을 사용해야만했을 것입니다.
: 스프링은 이에 대한 보다 유동적인 처리를 위하여 메시지 기능을 제공합니다
: 또한, 내가 영어권 사용자이면 'list', 'name'으로 표시될 수 있게끔하는 국제화 기능도 제공합니다.
: 이번 장에서는 앞서 언급한 메시지 기능, 국제화 기능에 대해 구체적으로 다뤄보려고 한다.
: 스프링부트를 사용하면 메시지 관리 기능을 제공하는 MessageSource
를 자동으로 스프링 빈으로 등록해줍니다.
: 이때 MessageSource
인터페이스의 내용은 다음과 같습니다.
public interface MessageSource{
// default 메시지 정의 가능
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
// 기본 코드
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
// MessageSourceResolvable 재정의 가능
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
: 스프링부트를 사용하지 않는다면 직접 등록해야만하는데 방법은 다음과 같다. 이 예제는 MessageSource
인터페이스의 구현체인 ResourceBundleMessageSource
를 스프링 빈으로 등록하는 예제입니다.
@Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenmaes("messages", "errors");
// basenames 세팅을 통해 설정 파일의 이름을 지정합니다.
// messages로 지정했으므로 -> messages.properties 파일을 읽습니다.
// 추가로 국제화 기능을 적용하려면 파일명 마지막에 언어정보를 주면 됩니다. ex) messages_en.properties..
// 국제화 파일이 없으면 messgaes.properties를 기본으로 사용합니다.
// 여러 파일을 한 번에 지정할 수도 있습니다. 위에서는 messages, errors 둘을 지정했습니다.
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
+) 추가로 ResourceBundleMessageSource 클래스에 대해 찾아보았습니다.
무언가 굉장히 복잡해보이지만 결국 예제에서 사용한 생성자 코드는
다음과 같음을 확인할 수 있었습니다.
: application.properties
에 다음과 같이 메시지 소스를 설정할 수 있습니다.
spring.messages.basename=messages, config.i18n.messages
config.i18n.messages 은 국제화를 위한 소스이다.
: 설정파일의 폴더 구조는 다음과 같다.
: 아래 예제에서 계속 사용할 properties는 다음과 같다.
MessageSource ms;
ms.getMessage("hello", null, null);
해당 코드의 결과물로는 mesages.properties
의 hello 값에 해당하는 "안녕"을 불러온다. locale정보가 없으면 basename에서 설정한 기본 이름 메시지 파일을 조회하기 때문이다. 기본 메시지도 없으면 해당 코드는 NoSuchMessageException
에러를 반환한다.
MessageSource ms;
ms.getMessage("no_code", null, "기본 메시지", null);
결과로는 "기본 메시지"가 출력된다. no_code라는 키 값을 기본 properties 파일에서 찾을 수 없기 때문이다.
MessageSource ms;
ms.getMessage("hello.name", new Object[]{"Spring!"}, null);
결과로는 "안녕 Spring!"이 출력된다. properties의 {0} 부분은 치환될 수 있고, 치환하기 위해서는 args에 Object 배열로서 값을 전달해주면 되기 때문이다.
ms.getMessage("hello", null, Locale.KOREA));
결과로는 "안녕"이 나온다. locale 정보가 있지만, messages_ko
가 없으므로 기본 properties가 나오는 것이다.
ms.getMessage("hello",null, Locale.ENGLISH);
결과로는 "hello"가 나온다. messages_en
설정파일을 사용하기 때문이다.
타임리프의 메시지 표현식을 사용하면 스프링 메시지를 편리하게 조회할 수 있습니다.
<div th:text="#{label.item}">
: 이런 방식을 사용하면 보다 쉽게 국제화 기능을 적용할 수 있게 됩니다.
: 스프링은 언어 선택시 기본으로 Accept-Language
헤더의 값을 사용합니다.
: 이때 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver
라는 인터페이스를 제공합니다.
: 스프링부트는 기본적으로 Accept-Language
를 활용하는 AcceptHeaderLocaleResolver
를 사용합니다.
: 이때 LocalResolver 인터페이스는
public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
다음과 같습니다.
: 디폴트 설정값인 AcceptHeaderLocaleResolver입니다.
: 해당 resolver를 사용하면 웹 브라우저의 locale 정보(Accept Language)에 따라 application의 locale 정보를 지정하게 됩니다.
: 메시지만 다국어로 분기했을 뿐, 아무것도 처리하지 않은 환경에서 사용하기 적합합니다.
: 실제로 많이 사용되는 localeResolver입니다.
: 말 그대로 Session에 Locale 정보를 박아넣고 이를 통해 다국어를 처리해주는 역할을 한다고 봅니다.
: 처음 들어갈때는 AcceptHeaderLocaleResolver처럼 브라우저의 언어 설정에 의한 Accept-Language로 값이 결정되는데 단, setDefaultLocale을 설정한다면 이 값이 최우선이 됩니다. 이는 세션으로 저장되며 org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE이라는 세션 속성 이름으로 클래스를 시리얼라이징 되어 저장합니다.
: LocaleResolver에 대해 설정을 넣는 방법은 다음과 같습니다.
: Config 파일에서 LocaleResolver에 대한 설정을 넣습니다.
@Bean
public SessionLocaleResolver localeResolver(){
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(new Locale("ko"));
// 기본 언어로 Ko를 설정.
return sessionLocaleResolver;
: session에 화면으로부터 넘어온 language라는 param 값으로 locale을 setting해줍니다. 이를 위한 컨트롤러 설정은 다음과 같스니다.
@RequestMapping(value="/changeLocale")
public void changeLocale(String language, HttpSession session){
session.setAttribute(SessionLocaleResolver.LOCLAE_SESSION_ATTRIBUTE_NAME, new Locale(language));
}
: 쿠기를 이용해서 Locale 정보를 담는 것입니다.
: setLocale()을 통해 Locale 정보를 담은 Cookie를 생성하고 resolveLocale()에서는 Cookie로부터 Locale 정보를 가지고 옵니다.
: 설정은 다음과 같습니다.
@Bean
public LocaleResolver localeResolver(){
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setCookieName("lang");
localeResolver.setDefaultLocale(new Locale("ko"));
localeResolver.setCookieHttpOnly(true);
return localeResolver;
}
: setLocale로 Cookie에 담을 수 있으며
@Autowired
LocaleResolver localeResolver;
@RequestMapping(value="/changeLocale")
public void changeLocale(String language, HttpServletRequest request, HttpServletResponse response){
Locale locale = new Locale(language);
localeResolver.setLocale(request, response, locale);
: resolverLocale을 사용해서 Cookie에 담긴 locale 정보를 가지고 올 수도 있다.
public static Locale getLocale(HttpServletRequest request){
Locale locale = localeResolver.resolveLocale(request);
return (locale != null)?(Locale)locale:getDefaultLocale();
}