메시지, 국제화

slee2·2022년 2월 3일
0

프로젝트 설정

mvc 2 안에서 message-start 폴더에 있는 프로젝트를 활용한다.

메시지와 국제화만을 다루기 위해서 이전에 다뤘던 설렉트 박스, 라디오 박스 없는 버전으로 사용한다.

메시지

여러 화면에서 보이는 상품명, 가격, 수량 등, label 에 있는 단어를 변경하려면 다음 화면들을 다 찾아가면서 모두 변경해야 한다.

작은 프로젝트일 경우에는 직접 찾아서 수기로 고치면 되지만, 프로젝트가 점점 커지면 일일이 고치는 것은 점점 골치아파질 것이다.

이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다.

예를 들어서 messages.properties라는 메시지 관리용 파일을 만들고

item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량

각 HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용하는 것이다.
<label for="itemName" th:text="#{item.itemName}"></label>

국제화

국제화란 쉽게 말해 메시지를 여러 언어로 하고싶다는 느낌이다.

message_en.properties

item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity

message_ko.properties

item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량

영어를 사용하는 사람이면 message_en.properties를 사용하고
한국이면 message_ko.properties를 사용하게 개발하면 된다.

한국에서 접근한 것인지 영어에서 접근한 것인지 알 수 있는 방법중에 대표적인 방법은 HTTP accept-language 헤더 값을 사용하는 방법이다.
그 외에는 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하는 방법이 있다.

스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다.
타임리프도 스프링이 지원하는 기능을 편리하게 사용할 수 있도록 제공해준다.

스프링 메시지 소스 설정

스프링은 기본적인 메시지 관리 기능을 제공한다.
메시지 관리 기능을 사용하려면 MessageSource를 스프링 빈으로 등록하면 되는데, MessageSource는 인터페이스이다. 그러므로 구현체인 ResourceBundleMessageSource를 스프링 빈으로 등록하면 된다.

직접 등록

@Bean
	public MessageSource messageSource() {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		messageSource.setBasenames("messages", "errors");
		messageSource.setDefaultEncoding("utf-8");
		return messageSource;
	}

basename: 설정 파일의 이름을 지정한다.
messages로 지정하면 messages.properties 파일을 읽어서 사용한다.
추가로 국제화 기능을 적용하려면 messages_en.properties, messages_ko.properties와 같이 파일명 마지막에 언어 정보를 주면 된다. 만약 찾을 수 있는 국제화 파일이 없으면 messages.properties를 기본으로 사용한다.

파일 위치는 /resources/messages.properties
여러 파일 지정가능하다. messages, errors 둘을 지정했다.

스프링 부트

스프링 부트를 사용하면 MessageSource를 자동으로 스프링 빈으로 등록한다.

application.properties

spring.messages.basename=messages,config.i18n.messages

스프링 부트 메시지 소스 기본 값
spring.messages.basename=messages

아무것도 설정안하면 messages라는 이름으로 기본 등록된다. 그러므로 message_en.properties, message_ko.properties, message.properties 파일만 등록하면 자동으로 인식된다.

혹시 옵션을 추가로 알고 싶다면,

https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties

여기서 검색하여 찾아볼 수 있다.

메시지 파일 만들기

기본값이 한글로 되어있으므로 영어가 아닌 다른 지역은 기본값인 한글로 보게 된다.

테스트

package hello.itemservice.message;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;

import java.util.Locale;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

    @Test
    void helloMessage() {
        String result = ms.getMessage("hello", null, null);
        assertThat(result).isEqualTo("안녕");
    }

    @Test
    void notFoundMessageCode() {
        assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
                .isInstanceOf(NoSuchMessageException.class);
    }

    @Test
    void notFoundMessageCodeDefaultMessage() {
        String result = ms.getMessage("no_code", null, "기본 메시지", null);
        assertThat(result).isEqualTo("기본 메시지");
    }

    @Test
    void argumentMessage() {
        String message = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        assertThat(message).isEqualTo("안녕 Spring");
    }

    @Test
    void defaultLang() {
        assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
        assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
    }

    @Test
    void enLang() {
        assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
    }
}

타임리프 메시지 적용

타임리프에서 메시지를 적용하려면
#{...} 라고 하면 된다.

렌더링 전
<div th:text="#{label.item}"></h2>

렌더링 후
<div>상품</h2>

이런 식으로 바꿔주면 된다.

파라미터는 다음과 같이 사용할 수 있다.
hello.name=안녕 {0}
<p th:text="#{hello.name(${item.itemName})}"></p>

웹 어플리케이션에 국제화 적용하기

이제 웹 어플리케이션에 영어를 적용시켜보자.

끝났다.

#{...}를 넣으면 그 값은 한국어도 있고 영어도 있는 것을 확인할 수 있다. 그러므로 우리가 해야할 일은 언어에 따라 바꿔지도록 설정해주면 되는데 이마저 스프링이 자동으로 해준다.

테스트를 위해 크롬 설정에서 언어를 가장 위로 설정해주고 실행하면

이렇게 영어로 바뀐것을 확인할 수 있다. 레전드

웹 브라우저 언어 설정 값을 변경하면 요청시 Accept-Language의 값이 변경되므로 그에 따라 바뀌게 된 것이다.

스프링의 국제화 메시지 선택

테스트에 있듯이 메시지 기능은 Locale 정보를 알아야 언어를 선택할 수 있다.

결국 스프링도 Locale 정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 Accept-Language 헤더의 값을 사용한다.

LocaleResolver

스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language를 활용하는 AcceptHeaderLocaleResolver를 사용한다.

public interface LocaleResolver {
    Locale resolveLocale(HttpServletRequest request);
    void setLocale(HttpServletRequest request, @Nullable HttpServletResponse
  response, @Nullable Locale locale);
}

국제화의 경우 어... 필요할때 사용하면 된다.

0개의 댓글