1. 메시지란?
만약, 기획자가 "상품명"이라는 단어를 모두 "상품 이름"으로 고쳐달라고 하며 어떻게 해야 할까? 만약, HTML 파일에 메시지가 하드코딩된 경우 경우 수십 개, 수백 개의 파일을 고쳐야 할 수 있다. 이런 문제를 해결하기 위해, 다양한 메시지를 한 곳에서 관리하도록 하는 기능이 메시지 기능이다. 예를 들어, messages.properties라는 메시지 관리용 파일에 다음과 같은 내용을 작성할 수 있다.
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
이렇게 되면 HTML에서 다음과 같이 해당 데이터를 key값으로 부를 수 있다.
<label for="itemName" th:text="#{item.itemName}"></label>
2. 국제화
한국에서 혹은 미국에서 접속하는 사이트의 경우 여러 언어를 지원해야 한다. 이런 경우 역시 메시지 관리용 파일(messages.properties)을 사용해 해결할 수 있다. 예를 들어, 각 나라별로 별도의 메시지 파일을 아래와 같이 만들 수 있다.
// 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=수량
이렇게 각 나라별 메시지 파일을 만들고, 이것을 적절하게 사용하기 위해서는 한국에서 접근했는지, 미국에서 접근했는지를 알고, 적절한 메시지 파일을 사용해야 한다. 이를 위해서 우리는 한국에서 접근했는지, 미국에서 접근했는지를 먼저 파악해야 하고, 이를 위해 아래와 같은 방법들을 활용할 수 있다.
- HTTP의 'accept-language' 헤더 값을 사용한다.
- 사용자가 직접 언어를 선택하게 한다.
- 쿠키를 활용한다.
메시지와 국제화 기능을 직접 구현할 수도 있지만, 스프링은 기본적인 메시지와 국제화 기능을 제공한다. 이러한 기능은 웹 어플리케이션을 개발자라면 기본적으로 모두 필요한 기능이다. 따라서 프레임워크에서 기본적으로 제공을 해주는 것이다. 또한 타임리프 역시 스프링이 제공하는 메시지와 국제화 기능을 편리하게 통합해서 제공한다. 그럼 지금부터 스프링이 제공하는 메시지와 국제화 기능을 살펴보자.
3. 스프링 메시지 소스 설정 및 사용
스프링은 기본적인 메시지 관리 기능을 제공한다. 메시지 관리 기능을 사용하기 위해서는 스프링이 제공하는 "MessageSource"를 스프링 빈으로 등록해야 한다. 단, "MessageSource"는 인터페이스이기 때문에 구현체인 "ResourceBundleMessageSource"를 스프링 빈으로 등록하면 된다.
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
- setBasenames: 설정 파일의 이름을 지정한다.
- messages로 지정하면 messages.properties 파일을 읽어서 사용한다.
- 국제화 기능을 적용하려면, "message_en.properties", "message_ko.properties"와 같이 파일명 마지막에 언어 정보를 주면 된다. 만약 찾을 수 있는 국제화 파일이 없다면, "message.properties"를 기본으로 사용한다.
- 파일의 위치는 "/resources" 폴더 아래에 두면 된다.
- 여러 파일을 한 번에 지정할 수 있다. 위에서는 "messages"와 "errors"를 지정한 것이다.
- setDefaultEncoding: 인코딩 정보를 지정한다.
MassageSource는 인터페이스로 다음과 같이 작성되어 있다.
public interface MessageSource {
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
- MessageSource의 메서드는 getMessage뿐이다. 해당 메서드는 받아온 파라미터들을 바탕으로 메시지를 읽어온다.
스프링 부트의 경우 자동으로 메시지 관리 파일들을 읽어서, 메시지와 국제화 두 기능을 모두 지원한다. 또한 "MessageSource"를 자동으로 스프링 빈으로 등록하여, 위와 같이 "MessageSource"를 빈으로 등록하는 코드가 필요없다. 스프링 부트에서는 "application.properties"에서 다음과 같이 메시지 소스를 설정할 수 있다. (설정하지 않으면 아래가 기본값이다.)
spring.messages.basename=messages
따라서 만약 스프링 부트에서 MessageSource를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 진행하지 않으면 기본 메시지 소스는 "messages"가 된다. 따라서 "messages_en.properties", "messages_ko.properties", "messages.properties" 파일만 등록해도 자동으로 인식된다.
- messages_en.properties는 영어에서 들어올 때, messages_ko.properties는 한국에서 들어올 때, messages.properties는 못 찾을 때 기본으로 주는 파일이다. 이 부분은 국제화에서 자세히 알아보자.
3.1. 메시지 파일 만들기
이제 메시지 파일을 만들어보자. 우리는 기본 값으로 한글을 사용하기 위해 messages.properties를 사용할 것이고, 영어 국제화를 위해 messages_en.properties를 활용할 것이다.
//messages.properties
hello=안녕
hello.name=안녕 {0}
//messages_en.properties
hello=hello
hello.name=hello {0}
3.2. 메시지 파일 사용
먼저 테스트 클래스는 다음과 같이 선언한다.
@SpringBootTest
public class MessageSourceTest {
@Autowired
MessageSource messageSource;
...
}
먼저 기본 메시지는 아무런 Locale을 전달하지 않거나 해당하는 Locale의 message 정보(파일)가 없을 때 가져온다.
@DisplayName("기본 메시지 가져오기")
@Test
void helloMessage() {
Assertions.assertThat(messageSource.getMessage("hello", null, null);).isEqualTo("안녕");
Assertions.assertThat(messageSource.getMessage("hello", null, Locale.KOREA);).isEqualTo("안녕");
}
- Locale을 null과 Locale.KOREA로 전달한 코드다. KOREA의 경우 관련된 메시지 파일이 없으므로 두 경우 모두 default message가 저장된 messages.properties에서 메시지를 가져온다.
메시지에 파라미터를 넘기고 싶다면 Object 배열을 넘겨줘야 한다.
@DisplayName("메시지에 파라미터 넘기기")
@Test
void argumentMessage() {
String result = messageSource.getMessage("hello.name", new Object[]{"Maru"}, null);
Assertions.assertThat(result).isEqualTo("hello Maru");
}
만약 기본 메시지가 아닌 다른 파일을 불러오고 싶다면 Locale 정보를 주면 된다. 우리의 경우 messages_en.properties가 있으므로 해당 메시지를 가져오고 싶다면 Locale.ENGLISH를 넘기면 된다.
@DisplayName("기본 메시지 말고 원하는 메시지 가져오기")
@Test
void messageInternationalizationTest() {
Assertions.assertThat(messageSource.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}
3.3. 타임리프 적용
타임리프에서 메시지를 가져오려면 아래와 같이 #{...}을 사용한다.
<h2 th:text="#{page.addItem}">상품 등록 폼</h2>
추가적으로 국제화를 위해서 spring은 LocaleResolver라는 인터페이스를 제공하며, 기본적으로 Accept-Langauge를 활용하는 AcceptHeaderLocaleResolver를 사용한다.
출처: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard
'BackEnd > Spring' 카테고리의 다른 글
[Spring DB-1] Connection Pool과 DataSource (0) | 2023.11.24 |
---|---|
[Spring DB-1] JDBC 이해 (0) | 2023.11.15 |
[Spring MVC-2] 타임리프 - 스프링 통합과 폼 (0) | 2023.09.27 |
[Spring MVC-2] 타임리프 - 기본 기능 (0) | 2023.09.25 |
[Spring MVC-1] 스프링 MVC - 웹 페이지 만들기 (0) | 2023.09.24 |