Spring/Spring MVC

스프링 메세지, 국제화

taey 2024. 10. 1. 02:01

메시지

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

 

message.properties라는 메시지 관리용 파일을 만들고

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

각 HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용하는 것이다.

//addForm.html
<label for="itemName" th:text="#{item.itemName}"></label>

//editForm.html
<label for="itemName" th:text="#{item.itemName}"></label>

 

국제화

메시지에서  설명한 메시지 파일을 각 나라별로 별도로 관리하면 서비스를 국제화할 수 있다.

message_en.properties, message_ko.properties

//message_en.properties
item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity
// emssage_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;
}
  • basenames : 설정 파일의 이름을 지정한다.
    • messages로 지정하면 messages.properties 파일을 읽어서 사용한다.
    • 추가로 국제화 기능을 적용하려면 messages_en.properties, messages_ko.properties와 같이 파일명 마지막에 언어 정보를 주면 된다. 만약 찾을 수 있는 국제화 파일이 없으면 messages.properties(언어 정보가 없는 파일명)를 기본으로 사용한다.
    • 파이르이 위치는 /resources/messages.properties에 두면 된다.
    • 여러 파일을 한 번에 지정할 수 있다. 여기서는 messages, errors 둘을 지정했다.
  • defaultEncoding : 인코딩 정보를 지정한다. utf-8을 사용하면 된다.

 

스프링 부트

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

 

스프링 부트 메시지 소스 설정

스프링 부트를 사용하면 다음과 같이 메시지 소스를 설정할 수 있다.

// application.properties
spring.messages.basename=messages, config.i18n.messages

 

스프링 부트 메시지 소스 기본 값

spring.messages.basename=messages

 

MessageSource를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages라는 이름으로 기본 등록된다. 따라서 messages_en.properties, messages_ko.properties, messages.properties 파일만 등록하면 자동으로 인식된다.

 


메시지 파일 만들기

/resources/messages.properties

messages.properties

hello=안녕
hello.name=안녕 {0}

/resources/messages_en.properties

messages_en.properties

hello=hello
hello.name=hello {0}

 


스프링 메시지 소스 사용

MessageSource 인터페이스

public interface MessageSource {
	String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
	String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
}
package hello.itemservice.message;

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 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("안녕");
	}
}

 

  • ms.getMessage("hello", null, null)
    • code : hello
    • args : null
    • locale : null

 

메시지가 없는 경우, 기본 메시지

@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("기본 메시지");
}
  • 메시지가 없는 경우에는 NoSuckMessageException이 발생한다.
  • 메시지가 없어도 기본 메시지(default Message)를 사용하면 기본 메시지가 반환된다.

 

매개변수 사용

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

 

다음 메시지의 {0} 부분은 매개변수를 전달해서 치환할 수 있다.

hello.name=안녕 {0} → Spring 단어를 매개변수로 전달 → 안녕 Spring

 

 

국제화 파일 선택

locale 정보를 기반으로 국제화 파일을 선택한다.

  • Locale이 en_US의 경우 messages_en_US → messages_en → messages 순서로 찾는다.
  • Locale에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고, 없으면 디폴트를 찾는다.
Locale 정보가 없는 경우 Locale.getDefault()을 호출해서 시스템의 기본 로케일을 사용합니다.
예) locale = null인 경우 →시스템 기본 locale이 ko_KR이므로 messages_ko.properties 조회 시도
→ 조회 실패 → messages.properties 조회

 

한글 깨짐이 발생하는 경우

인텔리제이에서 한글 깨짐이 발생하면 Setting - File Encodings로 이동하자.

  • Default encoding for properties files를 ISO-8859-1에서 UTF-8로 변경
  • Transparent native-to-ascil conversion 체