1.15.1 MesageSource를 사용한 국제화 by ks

ApplicationContext 인터페이스는 MessageSource라고 불리는 인터페이스를 확장하고, 그래서 국제화 ("i18n") 기능을 제공한다. 스프링은 또한 HierarchicalMessageSource 인터페이스를 제공하고, 계층적으로 메시지를 해결할 수 있다. 이 인터페이스들은 스프링이 메시지 해결에 영향을 주는 것을 기반으로 제공한다. 메소드들은 아래 인터페이스들을 정의한다.

i18n : internationaliztion(국제화)의 첫글자 끝글자 사이에 글자 수를 적어 표현한 단어. 여러 나라에서도 읽을 수 있게끔 하는 작업

  • String getMessage(String code, Object[] args, String default, Locale loc) : MessageSource로부터 메시지를 추출하는데 사용하는 기본 메소드. 구체적인 locale 메시지가 없을 때, 기본 메시지가 사용된다. 어떤 인자든 표준 라이브러리에 의해 제공된 MessageFormat 기능을 사용해서 값들을 대체한다.

  • String getMessage(String code, Object[] args, Locale loc) : 필수적으로 이전 메소드들과 같지만 다른점이 하나 있다 : 기본 메시지는 구체화할수없다. 만약 메시지가 발견되지 않으면 NoSuchMessageException이 반환된다.

  • String getMessage(MessageSourceResolvable resolvable, Locale locale) : 앞의 두개의 메소드들에서 사용하는 모든 프로퍼티들은 이 메소드에서 사용할 수 있는 MessageSourceResolvable이라고 불리는 클레스에 감싸진다.

ApplicationContext가 로드될 때, 자동적으로 context에 정의된 MessageSource 를 검색한다. 그 빈은 MessageSource라는 이름을 가져야만 한다. 만약 빈이 발견되면, 처리하는 메소드에서 부르는 모든 것들은 message source를 위임한다. 만약 message source가 발견되지 않으면, ApplicationContext는 같은 이름으로 된 빈을 포함하는 부모를 찾는다. 만약 그렇게 하면, MessageSource로서 빈을 사용한다. 만약 ApplicationContext가 메시지를 위한 어떠한 소스도 발견하지 못한다면, 비어있는 DelegatingMessageSource를 인스턴스화해서 위에서 정의된 메소드에 대한 호출을 받을 수 있도록 한다.

스프링은 두개의 MessageSource 확장자 - ResourceBundleMessageSource와 StaticMessageSource를 제공한다. 두개 모두 메시징을 감싸기 위해 HierarchicalMessageSource를 확장한다. StaticMessageSource는 거의 사용되지 않지만 소스에 메시지를 더하는 프로그래밍적 방법을 제공한다. 아래는 ResourceBundleMessageSource를 사용한 예제다.

<beans>
    <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>format</value>
                <value>exceptions</value>
                <value>windows</value>
            </list>
        </property>
    </bean>
</beans>

클래스패스에서 정의된 windows, exceptions, format이라 불리는 세개의 리소스 번들을 가진다고 가정한다. 어떠한 요청이든 ResourceBundle오브젝트를 통해 메시지를 풀기위한 JDK 표준법으로 다뤄진다. 리소스 번들 파일 두가지 내용이 다음과 같다.

format.properties 파일

# in format.properties
message=Alligators rock!

exception.properties 파일

# in exceptions.properties
argument.required=The {0} argument is required.

다음 예제는 MessageSource 기능을 실행하기 위한 프로그램을 보여준다. 모든 ApplicationContext 확장자들은 MessageSource를 확장하고, 그래서 MessageSource 인터페이스로 캐스팅할 수 있다는 것을 기억해라.

public static void main(String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("message", null, "Default", null);
    System.out.println(message);
}

아래는 결과다.

Alligators rock!

요약하자면, MessageSource는 beans.xml(클래스패쓰의 루트에 존재하는) 이라 불리는 파일 안에 정의되어있다. MessageSource빈은 basenames프로퍼티를 통해 리소스 번들 중 하나를 참조한다. basenames 프로퍼티에 리스트를 넘기는 세개의 파일은 클래스패스의 루트에 파일로서 존재하고 format.properties, exceptions.properties, windows.properties라고 불린다.

다음 예제는 message lookup으로 넘기는 인자들을 보여준다. 이 인자들은 문자열 오브젝트로 변환되고 lookup 메시지에 placeholders로 입력된다.

<beans>

    <!-- this MessageSource is being used in a web application -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="exceptions"/>
    </bean>

    <!-- lets inject the above MessageSource into this POJO -->
    <bean id="example" class="com.something.Example">
        <property name="messages" ref="messageSource"/>
    </bean>

</beans>

public class Example {

    private MessageSource messages;

    public void setMessages(MessageSource messages) {
        this.messages = messages;
    }

    public void execute() {
        String message = this.messages.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", null);
        System.out.println(message);
    }
}

execute메소드가 실행된 결과다.

위에 제공하는 메소드 설명을 보면 돼. argument.required라는 메시지를 쓸거고, "Required"는 해당 메시지가 없을 때 사용할 기본 메시지야. userDao는 배열들 중에 0번째라서 아래와 같이 출력이 돼.

The userDao argument is required.

국제화 (i18n)와 관련해서 스프링의 여러가지 MessageResource 구현체는 표준 JDK ResourceBundle과 같은 로케일(locale) 처리방법과 장애복구 규칙을 따른다. 간단히 말해서, 이전에 정의한 messageSource 예제를 계속하는 것은, 만약 영국(en-GB) locale에 대응하여 메시지를 풀기를 원한다면, format_en_GB.properties, execption_en_GB.properties, windows_en_GB.properties를 대표적으로 생성해야한이다.

전형적으로 locale 확장자는 어플리케이션의 환경에 의해 관리된다. 아래 예제는 영국 메시지를 수동으로 구체화하여 대응한다.

# in exceptions_en_GB.properties
argument.required=Ebagum lad, the {0} argument is required, I say, required.

public static void main(final String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("argument.required",
        new Object [] {"userDao"}, "Required", Locale.UK);
    System.out.println(message);
}

프로그램에서 실행한 결과다.

Ebagum lad, the 'userDao' argument is required, I say, required.

정의했었던 어떠한 MessageSource라도 참조한 MessageSourceAware 인터페이스를 사용할 수 있다. MessageSourceAware인터페이스를 확장하는 ApplicationContext에서 정의된 어떠한 빈이라도 어플리케이션 컨텍스트의 MessageSource에 주입된다. 빈이 생성되고 설정됐을때.

ResourceBundleMessageSource에 대적으로 스프링은 ReloadableResourceBundleMessageSource 클래스를 제공한다. 이 변수는 번들 파일 포맷과 같지만 ResourceBundleMessageSource 확장에 기반한 표준 JDK보다 더 유연하다. 부분적으로 이는 클래스패스뿐 아니라 리소스 위치로부터 파일을 읽어들이고, 번들 프로퍼티 파일 핫 리로딩을 지원한다.(효과적으로 그것들 사이를 캐싱하는 동안). ReloadableResourceBundleMessageSource 문서를 보자.

참조 : http://egloos.zum.com/poohya/v/845689

ReloadableResourceBundleMessageSource는 프로퍼티 파일이 변경되었을 때 앱을 다시 시작할 필요없이 변경이 적용된다.

Last updated