Message
기획자가 화면에 보이는 문구를 변경해달라는 상황이다, 상품명이라는 단어를 모두 상품이름으로 고쳐달라고 하면 어떻게 해야할까?
그러면 많은 화면에 해당하는 수십개의 파일을 수정해야 한다...
이를 유연하게 대처할 수 있는 방법은 뭐가 있을까?
messages.properties
메세지 관리용 파일을 만드는 것이다!
item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량
이런식으로 한 곳에 작성해두고, 필요시에 각 HTML 태그에서 해당 데이터를 Key 값으로 불러 사용하는 것이다.
그럼 해당 데이터를 어떻게 불러 사용할까?
<label for="itemName" th:text="#{item.itemName}"></label>
위의 예시와 같이 th:text = "#{...}" 형식을 맞춰 사용해줘야 한다.
위와 같이 작성하면 렌더링 후 → 상품명 이 웹에 출력된다.
국제화
위에서 설명한 메세지 관리용 파일을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다.
예를 들어 아래와 같이 한글 파일과 영어 파일을 나누는 것이다.
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=수량
영어를 사용하는 사람이면 messages_en.properties 를 사용하고,
한국어를 사용하는 사람이면 messages_ko.properties 를 사용하게 개발하면 된다.
한국에서 접근한 것인지 영어에서 접근한 것인지는 인식하는 방법은 HTTP accept-language 헤더 값을 사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키, 세션 등을 사용해서 처리하면 된다.
스프링도 Locale 정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 AcceptLanguage 헤더의 값을 사용한다.
스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.
만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다.
예 - 고객이 직접 Locale 을 선택
스프링 메시지 소스 설정
메시지 관리 기능을 사용하려면 스프링이 제공하는 MessageSource 를 스프링 빈으로 등록하면 되는데,
MessageSource 는 인터페이스이다. 따라서 구현체인 ResourceBundleMessageSource 를 스프링 빈으로 등록하면 된다.
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new
ResourceBundleMessageSource();
messageSource.setBasenames("messages", "errors");
messageSource.setDefaultEncoding("utf-8");
return messageSource;
}
이는 스프링 빈으로 직접 등록 하는 방법이다.
BUT,
스프링 부트를 사용하면 스프링 부트가 MessageSource 를 자동으로 스프링 빈으로 등록한다.
다음과 같이 application.properties 에 메세지 소스를 설정을 따로 할 수가 있다.
spring.messages.basename=messages,config.i18n.messages
따로 설정을 하지 않는다면, 아래와 같이 messages가 기본값으로 설정된다.
spring.messages.basename=messages
따라서, messages_en.properties , messages_ko.properties , messages.properties 파일만 등록하면 자동으로 인식된다.
EX)
messages.properties 경로 : /resources/messages.properties
hello=안녕
hello.name=안녕 {0}
messages_en.properties 경로 : /resources/messages_en.properties
hello=hello
hello.name=hello {0}
스프링 메시지 소스 사용 - Test
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;
MessageSource 인터페이스를 보면 코드를 포함한 일부 파라미터로 메시지를 읽어오는 기능을 제공
@TEST
@SpringBootTest
public class MessageSourceTest {
@Autowired
MessageSource ms;
@Test
void helloMessage() {
String result = ms.getMessage("hello", null, null);
assertThat(result).isEqualTo("안녕");
}
}
code는 hello, arg는 없기 때문에 null, locale은 설정하지 않아 null로 했다.
결과는 기본 한국어로 되어 있기 때문에 "안녕" 이 출력된다.
@Test - 메세지가 없는 경우, 기본 메세지
@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("기본 메시지");
}
해당하는 코드가 없을 때는 NoSuchMessageException 이 발생한다.
만일, 해당하는 코드가 없는데 DefaultMessage를 위와 같이 설정해준다면, DefaultMessage가 출력된다.
위에서는 "기본 메세지" 라고 작성해두었다.
@Test - 매개 변수 사용
@Test
void argumentMessage() {
String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(result).isEqualTo("안녕 Spring");
}
매개 변수는 new Object[]{"..."} 을 통해 전달한다.
hello.name=안녕 {0} → Spring 단어를 매개변수로 전달 → 안녕 Spring
국제화 파일 선택
locale 정보를 기반으로 국제화 파일을 선택한다.
Locale이 en_US 의 경우 messages_en_US → messages_en → messages 순서로 찾는다.
Locale 에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고, 없으면 디폴트를 찾는다고 이해하면 된다.
웹 애플리케이션에 국제화 적용
위에서 말한 방식대로 HTML 파일에서 해당 부분을 변경해주면 된다.
<h2>상품 등록 폼</h2> -> <h2 th:text="#{page.addItem}">상품 등록</h2>
만약, 파라미터를 사용해야 한다면?
hello.name=안녕 {0}
<p th:text="#{hello.name(${item.itemName})}"></p>
위와 같은 형식으로 작성해줘야 한다. → #{...(${...})}
'Spring' 카테고리의 다른 글
Spring 검증 - Validator (0) | 2023.12.19 |
---|---|
Spring 검증 - BindingResult (FieldError, ObjectError, rejectValue, reject) (1) | 2023.12.18 |
Spring - ArgumentResolver 활용 (0) | 2023.09.26 |
Spring- 필터, 인터셉터(Filter, Interceptor) (0) | 2023.09.18 |
Spring- 쿠키, 세션(Cookie, Session)[로그인] (0) | 2023.09.18 |