2018년 7월 20일 금요일

Spring Boot Internationalization(다국어 지원)

 Spring Boot로 Web app을 개발할 때 다국어 지원을 어떻게 할 것인가에 대해서 대부분 한 번쯤은 고민을 해보았을 것이다. 그 때마다 항상 인터넷을 뒤져서 처리하곤 했는데 생각이 난 김에 필요할 때 참고하기 좋도록 여기에 정리해볼까 한다.

 Spring Boot의 가장 큰 장점은 대부분의 설정이 이미 되어있어서 별로 설정하지 않아도 웬만큼 쓸만하게 돌아간다는 것이다. MessageSource 설정도 역시 이미 되어있다. 기억해두어야 할 건 한 가지 뿐이다. 아래 그림과 같이 resources 폴더 아래에 messages.properties 파일이 MessageSource의 리소스 파일로 사용된다는 것이다. 그림은 IntelliJ 에서의 캡쳐 화면이다.


 확장자를 보면 알겠지만 포맷은 properties 파일 포맷(key=value)이다. 이 파일에 다국어 대상의 메시지들을 등록해 놓으면 JSP나 Thymeleaf 엔진에서 바로 사용이 된다.

 간단하게 Thymeleaf를 예로 들어보자. 아래 내용을 messages.properties 파일에 넣는다.

login.welcome-msg=Welcome!

messages.properties 파일의 내용이 위와 같다고 하면 Thymeleaf용 template 파일에서는 아래와 같이 사용이 가능하다.

  ...
  <div>
    <span th:text="#{login.welcome-msg}">Some Text</span>
  </div>
  ...

 위 파일에서 th:text 속성에 #{login.welcome-msg}를 지정함으로써 messages.properties 파일에 등록된 login.welcome-msg의 값이 span 태그의 텍스트 값(Some Text) 대신에 교체되어 html 파일이 생성되는 것이다. JSP에서의 사용법은 많이들 알고 있을 것이므로 따로 설명하지 않겠다.

 현재 상태에서는 messages.properties 파일 하나밖에 없기 때문에 모든 locale에 대해서 messages.properties 파일이 사용된다. 사실 messages.properties 파일은 locale을 판단할 수 없을 때 default로 사용되는 파일이고 원하는 locale에 대해서 messages_XX.properties 형태로 파일을 추가함으로써 해당 언어를 지원할 수 있다. 예를 들어 한국어를 지원하려면 messages_ko.properties 형태로 파일을 만들어서 resources 폴더 안에 넣어두기만 하면 된다. ko는 언어코드만 지정되었지만 구체적으로 국가 코드까지 포함된 ko-KR을 지정하고 싶다면 messages_ko_KR.properties 형태로 파일을 만들면 된다.

 messages_ko.properties 파일을 추가해주면 IntelliJ에서는 관리하기 편리하도록 아래 그림과 같이 묶어서 보여준다.


 그럼 Locale을 판단하는 방법은 무엇일까? Spring에서는 LocaleResolver 인터페이스를 구현한 Bean을 등록하여 등록된 Bean이 Locale을 판단하도록 하고 있다. 아무런 설정을 하지 않은 상태에서는 AcceptHeaderLocaleResolver가 기본으로 등록되어 사용된다. AcceptHeaderLocaleResolver는 HTTP Request의 "accept-language" 헤더의 값을 이용해서 Locale을 판단한다. 현재 대부분의 Major 브라우저들은 요청에 이 헤더를 포함시켜서 요청을 하기때문에 별 설정을 하지 않아도 잘 동작한다.

 그런데 만약 사용자가 직접 언어를 선택할 수 있는 기능이 필요하다면 사용자가 선택한 Locale 값을 Session이나 Cookie에 저장해서 그 값을 이용하도록 해야한다. 이런 경우라면 SessionLocaleResolver나 CookieLocaleResolver를 LocaleResolver로 등록해주면 된다. 이것들은 각각 Session이나 Cookie에 포함된 특정 attribute의 값을 기준으로 Locale을 판단하며 해당 attribute가 없으면 AcceptHeaderLocaleResolver와 같이 "accept-language" 헤더의 값으로 Locale을 판단한다. 자세한 사항은 Spring Framework 문서를 참조하길 바란다.

 Spring Boot에서 원하는 LocaleResolver를 bean으로 등록하는 방법은 Application 클래스에 아래와 같은 메소드를 등록해주면 된다.

@SpringBootApplication
public class UserServiceApplication {

    ...

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.US);
        return localeResolver;
    }
}

 HTTP request의 헤더나 Session, Cookie가 아닌 HTTP request의 parameter를 이용해서 Locale을 바꾸는 방법도 있다. HTTP request의 parameter를 이용하려면 LocaleChangeInterceptor를 Interceptor로 등록해주면된다. LocaleChangeInterceptor는 "locale=xx" 형태의 parameter를 받아서 Locale을 바꿔준다. 예를 들어 요청 URL이 "http://www.somesite.com/?locale=ko"라면 Locale을 한국어로 바꾸어주는 것이다. parameter의 이름을 "locale"이 아닌 다른 값으로 바꿀 수도 있다. 자세한 사항은 Spring Framework의 문서를 참조하길 바란다.

 LocaleChangeInterceptor를 등록하는 방법도 간단하다. 아래 코드에서 보듯이 Application 클래스가 WebMvcConfigurer를 implement하도록 하고 두 메소드를 추가하는 것이다.

@SpringBootApplication
public class UserServiceApplication implements WebMvcConfigurer {

    ...

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        return lci;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }
}

 메소드 이름에서 짐작하겠지만 첫 번째 메소드는 LocaleChangeInterceptor를 bean으로 등록하는 것이고 두 번째 메소드는 등록된 LocaleChangeInterceptor bean을 Interceptor로 등록(추가)하는 것이다.

 한 가지 더 추가로 얘기하자면 스프링 5.0 이전 버전에서는 WebMvcConfigurerAdapter를 상속해야 했지만 5.0부터는 WebMvcConfigurer 인터페이스에 default method가 추가되어 WebMvcConfigurer 인터페이스를 직접 구현하도록 바뀌었으므로 참고하도록 하자.

댓글 1개: