[Spring] 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 섹션3 메시지, 국제화
◼️ 메시지, 국제화
메시지 기능: 다양한 메시지를 한곳에서 관리하도록 하는 기능
messages.properties
( /resources/messages.properties )
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
HTML들은 아래와 같이 데이터를 key 값으로 불러서 사용
<label for="itemName" th:text="#{item.itemName}"></label>
<label for="itemName" th:text="#{item.itemName}"></label>
국제화: 메시지 파일을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다. 어느 나라에서 접근한 것인지 인식은 HTTP accept-language 해더 값, 사용자가 직접 언어를 선택, 쿠키 등을 사용해 처리한다.
messages_en.properties
item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity
messages_ko.properties
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
◼️ 스프링 메시지 소스 설정
메시지 관리 기능을 사용하려면 스프링이 제공하는 MessageSource를 스프링 빈으로 등록한다.
🟢 직접 등록 방법
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
🟢 스프링 부트
스프링 부트를 사용하면 스프링 부트가 MessageSource 를 자동으로 스프링 빈으로 등록한다.
application.properties
spring.messages.basename=messages,config.i18n.messages
스프링 부트 메시지 소스 기본 값
spring.messages.basename=messages
MessageSource 를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라 는 이름으로 기본 등록된다. 따라서 messages_en.properties , messages_ko.properties , messages.properties 파일만 등록하면 자동으로 인식된다.
메시지 파일 만들기
- messages.properties :기본 값으로 사용(한글)
- messages_en.properties : 영어 국제화 사용
/resources/messages.properties
hello=안녕
hello.name=안녕 {0}
/resources/messages_en.properties
hello=hello
hello.name=hello {0}
◼️ 스프링 메시지 소스 사용
MessageSource 인터페이스를 보면 코드를 포함한 일부 파라미터로 메시지를 읽어오는 기능을 제공한다.
// 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;
메시지 코드를 읽는 테스트 코드를 보자.
@SpringBootTest
public class MessageSourceTest {
@Autowired
MessageSource ms;
@Test
void helloMessage() {
String result = ms.getMessage("hello", null, null); // code,args,locale
assertThat(result).isEqualTo("안녕");
}
}
locale 정보가 없으면 basename에서 설정한기본 이름 메시지 파일( messages.properties )을 조회한다.
@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("기본 메시지"); //defaultMessage;메시지가 없어도 기본메시지 반환
}
@Test
void argumentMessage() { // {0} 매개변수 치환
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(result).isEqualTo("안녕 Spring");
}
국제화 파일 선택
- locale 정보를 기반으로 국제화 파일을 선택
- Locale 정보가 없는 경우 Locale.getDefault() 을 호출해서 시스템의 기본 로케일을 사용
- Locale이 en_US 의 경우 messages_en_US messages_en messages 순서로 찾는다.
- Locale 에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고, 없으면 디폴트를 찾는다.
@Test
void defaultLang() {
// locale X; default사용
assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
// locale O,message_ko X; messages사용
assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
}
@Test
void enLang() {
// locale 정보가 Locale.ENGLISH 이므로 messages_en 을 찾아서 사용
assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}
◼️ 웹 애플리케이션에 메시지 적용하기
messages.properties
label.item=상품
label.item.id=상품 ID
label.item.itemName=상품명
label.item.price=가격
label.item.quantity=수량
page.items=상품 목록
page.item=상품 상세
page.addItem=상품 등록
page.updateItem=상품 수정
button.save=저장
button.cancel=취소
타임리프의 메시지 표현식 #{...} 를 사용해 스프링의 메시지를 조회할 수 있다.
렌더링 전
<div th:text="#{label.item}"></h2>
렌더링 후
<div>상품</h2>
◼️ 웹 애플리케이션에 메시지 적용하기
messages_en.properties
label.item=Item
label.item.id=Item ID
label.item.itemName=Item Name
label.item.price=price
label.item.quantity=quantity
page.items=Item List
page.item=Item Detail
page.addItem=Item Add
page.updateItem=Item Update
button.save=Save
button.cancel=Cancel
이것으로 국제화 작업은 거의 끝났다. 앞에서 템플릿 파일에는 모두 #{...} 를 통해서 메시지를 사용하도록 적용해두었기 때문이다.
크롬 브라우저 → 설정 → 언어를 검색후, 우선 순위를 변경하면 요청시 Accept-Language 의 값이 변경된다.
(Accept-Language 는 클라이언트가 서버에 기대하는 언어 정보를 담아서 요청하는 HTTP 요청 헤더이다.)
◼️ 스프링의 국제화 메시지 선택
앞서 보았듯 메시지 기능은 Locale 정보를 알아야 언어를 선택할 수 있다.
스프링은 언어 선택시 기본으로 AcceptLanguage 헤더의 값을 사용한다.
🟢 LocaleResolver
- 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공
- 스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용
public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}
🟢 LocaleResolver 변경
만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다. 예를 들어서 고객이 직접 Locale 을 선택하도록 하는 것이다.
'Spring' 카테고리의 다른 글
[Spring] 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 섹션6 로그인 처리1 - 쿠키, 세션 (0) | 2024.05.08 |
---|---|
[Spring] 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 섹션4 검증1 - Validation (1) | 2024.05.06 |
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 섹션7 스프링 MVC - 웹 페이지 만들기 (0) | 2024.04.24 |
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 섹션6 스프링 MVC - 기본 기능 (1) | 2024.04.21 |
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 섹션5 스프링 MVC - 구조 이해 (0) | 2024.04.17 |