[Spring] 국제화, 메시지, 다국어 지원

dondonee·2023년 11월 3일
0
post-thumbnail

국제화, 메시지, 다국어 지원

다양한 사용자의 언어 및 지역에 맞춤 서비스를 제공하는 것을 국제화라고 한다. 영어로는 Internationalization인데 줄여서 i18n이라고도 한다. i, n 사이에 18자가 생략되었다는 의미이다.

국제화를 위해서는 특정 지역과 언어별로 "로케일"을 구성하여 그에 맞에 소프트웨어를 구성하는 지역화(Localization, l10n)가 필요하다. Java는 로케일을 나태낼 수 있도록 java.util.Locale 객체를 제공한다.


Locale 객체

로케일은 언어와 지리적 지역을 식별한다. 로케일에 따라 사용자에게 데이터를 표시하는 방법이 달라진다. 기본적인 언어, 대소문자 표시, 데이터 정렬, 날짜 및 시간 형식, 숫자 및 통화 형식에 영향을 준다.

java.text.NumberFormatjava.text.DateFormat와 같이 locale-sensitive한 클래스는 로케일 정보에 따라 숫자나 날짜의 형식을 지역화하여 표시해준다.

미리 만들어져 있는 Locale 상수

자주 사용되는 로케일은 static 객체로 이미 만들어져 있다. (권장 X)

public final class Locale implements Cloneable, Serializable {

  public static final Locale KOREAN = createConstant("ko", "");
	public static final Locale KOREA = createConstant("ko", "KR");
}
  • Locale.KOREAN, Locale.KOREA
  • Locale.ENGLISH, Locale.US, Locale.UK

그러나 아무래도 만들어져있는 로케일은 몇 종류 없다. 로케일 상수가 없는 새로운 로케일을 추가한다면 코드의 일관성이 깨지게 된다. 또한 locale-sensitve한 클래스들이 로케일 상수가 존재하는 로케일에만 지역화를 지원하는 것도 아니다. 예를 들어 남미 로케일 상수는 존재하지 않지만 locale-sensitve한 클래스들이 지역화를 아주 잘 지원한다.

이러한 이유로 로케일은 그냥 생성자로 만드는 것이 좋다고 한다.

생성자

Locale은 세 가지 생성자를 갖고 있다.

  • Locale(String language)
  • Locale(String language, String country)
  • Locale(String language, String country, String variant)

사용 예시

//일반적인 영어를 사용하는 로케일 생성
Locale locale1 = new Locale("en");
    
//영어 사용, 캐나다 지역의 로케일 생성
Locale locale2 = new Locale("en", "CA");
    
//영어 사용, 미국 지역, 실리콘밸리의 로케일 생성
Locale locale3 = new Locale("en", "US", "SiliconValley");

파라미터

생성자 파라미터의 language는 소문자, country는 대문자이다.

  • language: ISO 640의 alpha-2(알파벳 2자) 또는 alpha-3(알파벳 3자) 또는 8자 이하의 언어 하위태그를 사용한다.
  • country: ISO 3166 alpha-2 국가 코드 또는 UN M.49 numeric-3 지역 코드를 사용한다.
  • variant: 로케일을 세분화하기 위해 지원하는데 자주 사용되지 않는 것 같다.

참고) new Locale(”hello”)처럼 아무 값이나 넣어도 컴파일 오류가 나지는 않는다. Locale은 아무 것이나 만들 수는 있지만 사용하는 라이브러리 등에서 지원하는가의 문제이다.


메시지에 대해

메시징(Messaging)이란 국제화를 위한 핵심 기능이다. 표시하고자 하는 문자열을 단순하게 리터럴로 표시하지 않고, 별도의 메세지 관리 파일에서 키를 통해 값을 찾아와 표시하는 방법이다.

메시지 관리 파일을 언어 별로 만들면, 동일한 키를 가지고 다양한 언어의 값을 가져올 수 있다. 예를 들어 “greeting”이라는 키 하나만 있으면 사용자의 로케일에 맞게 “안녕하세요?”, “Hi.”, “こんにちは。” 등으로 맞춤 문자열을 가져올 수 있다.

사용법

  1. 메시지 소스 설정하기: 스프링 부트를 사용한다면 바로 사용할 수 있다. 그렇지 않다면 MessageSource 빈을 등록해주어야 한다.

    @Bean
    public MessageSource messageSource() {
    	ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    	messageSource.setBasenames("messages", "errors");
    	messageSource.setDefaultEncoding("utf-8");
    	return messageSource;
    }
  2. 메시지 관리 파일 만들기: resources 바로 밑에 messages.properties를 만들어준다.

    • messages.properties는 디폴트 파일이다. 특정 로케일이 없는 경우 선택된다. 기본적으로 관리 파일의 이름(basename)은 messages인데 설정을 통해 변경 가능하다.
    • 국제화를 하고 싶다면 basename 바로 뒤에 언더바와 함께 로케일 정보를 붙여준다. messages_en.properties, messages_ko_KR.properties와 같은 형식이다.
  3. 메시지 불러오기:

    • MessageSource 인터페이스의 getMessage() 메서드를 통해 불러올 수 있다.
      String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
    • Thymeleaf 템플릿의 경우 th:text=”#{key}" 문법을 통해 메시지를 표시할 수 있다.

관련 인터페이스

메시지, 국제화 기능을 위한 핵심 인터페이스는 MessageSourceLocaleResolver이다.

스프링은 기본적으로 클라이언트의 Locale 정보를 기준으로 해당하는 MessageSource를 찾는다. 즉 Locale 값을 변경함으로써 다국어 지원을 할 수 있는 것이다.

그렇다면 Locale 정보는 어떻게 정해지는 것일까? 기본적으로는 HTTP Accept-Language 헤더를 참고하여 정해진다. 그리고 이 역할을 하는 것이 LocaleResolver이다. (참고로 이 헤더의 값은 클라이언트의 브라우저, OS 등 환경에 따라 달라진다.)

구현 클래스

로케일 선택 전략을 바꾸고 싶다면 LocaleResolver 인터페이스의 구현체를 변경하면 된다.

  • AcceptHeaderLocaleResolver
    • Accept-Language 헤더를 참고하여 로케일을 설정한다. 로케일을 지정하는 setLocale() 메서드는 없으며 클라이언트의 설정 변경을 통해서만 로케일 변경이 가능하다.
    • LocaleResolver의 기본 구현체이다.
  • FixedLocaleResolver
    • 고정된 로케일을 반환한다. 기본적으로 JVM의 기본값을 사용하며 setLocale() 메서드는 없다.
  • SessionLocaleResolver
    • 세션의 로케일 정보를 사용한다. 로케일은 각 서블릿 컨테이너마다 관리되므로 세션이 종료되면 로케일 정보도 사라진다.
    • 보조적으로 디폴트 로케일이나 Accept-Language 헤더 정보, 서버의 로케일 정보를 사용한다. 애플리케이션에 HttpSession이 사용되는 경우 가장 적합하다(로케일 저장만을 위한 세션 생성이 아닌 경우).
    • Spring Session과 같은 외부 세션 관리 매커니즘과는 직접적인 관련이 없으며 단순히 HttpServletRequest에 대한 HttpSession을 관리한다.
  • CookieLocaleResolver
    • 쿠키의 로케일 정보를 사용한다.
    • 보조적으로 디폴트 로케일이나 Accept-Language 헤더 정보, 서버의 로케일 정보를 사용한다. 사용자 세션을 사용하지 않는 Stateless 애플리케이션에 특히 유용하다.

🔗 References

0개의 댓글