framework/spring

스프링 mvc2 - 1 메시지, 국제화

wooweee 2023. 5. 13. 01:33
728x90

1. 메시지, 국제화 소개

  • messages.properties : key-value로 메시지 관리 file 생성

 

1.1. 메시지

  • 메시지: 동일한 단어를 일일이 변경하는 까다로움을 해결하기 위해서 다양한 메시지를 한 곳에서 관리하도록 하는 기능

 

방식

  • 경로: resources/messages.properties
hello=안녕
hello.name=안녕 {0}

 

  • 사용: thymeleaf에서 메시지 key를 불러서 value를 사용 : #{messageKEY}
<label for="itemName" th:text="#{item.itemName}"></label>

 

1.2. 국제화

  • 경로: resources/messages_en.properties
hello=hello
hello.name=hello {0} 

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

 

  • 경로: resources/messages_ko.properties
hello=안녕
hello.name=안녕 {0}

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=취소

 

  • 한국어 영어 인식하는 방법
    1. http accept-language 헤더 값을 사용
    2. web Browser 설정
    3. 사용자가 직접 언어를 선택하도록 쿠키를 사용해서 처리하기 (구글링하면 많이 나옴)

 

  • 메시지와 국제화 기능을 직접 구현 가능하지만 스프링이 기본적으로 제공함

 

2. 스프링 메시지 소스 설정

 

2.1. 직접 등록

  • 스프링이 제공하는 MessageSource를 springBean으로 등록

  • MessageSource
    • interface
    • MessageSource의 구현체인 ResourceBundleMessageSource를 스프링 빈으로 등록

 

// spring이 등록한 빈
@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    
    // "messages" : messages.property
    // "errors" : errors.property
    messageSource.setBasenames("messages", "errors");
    
    messageSource.serDefaultEncoding("utf-8);
    return messageSource;
}

 

  • setBasenames: 설정 파일의 이름 지정
    • messages: messages.properties 파일을 읽어서 사용
      -> 꼭 messages 로 파일 이름을 설정하지 않아도 된다.

    • 국제화 적용
      파일명 마지막에 언어 정보 추가 ex)_en.properties , _ko.properties

    • 설정 파일 위치
      /resources/messages.properties

    • 여러 파일을 한번에 설정 가능
      messages, errors -> messages.properties, errors.properties 2개 설정 파일

 

  • setDefaultEncoding: 인코딩 정보를 지정하는데 utf-8 사용

 

2.2. 스프링 부트

  • MessageSource를 자동으로 스프링 빈으로 등록

  • 스프링부트 메시지 소스 설정
    • SetBasenames("file명", "file명") 과 같은 역할

    • application.properties 에서 설정 변경

    • default 값
      • spring.messages.basename=messages
      • value : utf-8

 

#파일 위치: application.properties
spring.messages.basename=messages, errors  # <- errors.properties 추가

 

3. 메시지 소스 사용 

  • interface의 method 사용 소개
// MessageSource interface

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 interface
  • getMessage(   basenames.properties KEY 명,   Object 배열,   찾을 수 없을 때 defaultMessage,  국제화   )

 

# 2개 파일의 code를 한 코드 블럭에 넣음

/resources/messages.properties
hello=안녕
hello.name=안녕 {0}


/resources/messages_en.properties
hello=hello
hello.name=hello {0}
  • {0}: Object 배열의 첫번째를 가지고 온다는 뜻
  • 참고: thymeleaf에서는 #{hello.name(${item.itemName})} 형태로 사용 

 

//사용 test code

@SpringBootTest
public class MessageSourceTest {

    // 참고
    // SpringBootTest여서 MessageSource가 자동으로 springBean 생성이 된다.
    // @Test에서 MessageSource method를 직접 사용해서 test를 하기 위해서 의존관계 주입을 넣는다.
    // 실제 spring에서 사용할때는 html에서 사용을 하기 때문에 thymeleaf의 문법을 통해서 더 간단하게 사용한다.
    @Autowired
    MessageSource ms;

    @Test
    void helloMessage() {
        String result = ms.getMessage("hello", null, null);
        // messages.proerties KEY명, object 배열 null, locale 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);
        // messages.proerties KEY명, object 배열 null, default message, locale null
        assertThat(result).isEqualTo("기본 메시지");
    }
    
    // 매개변수 사용
    @Test
    void argumentMessage() {
        String message = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        // messages.proerties KEY명, object 배열, locale null
        assertThat(message).isEqualTo("안녕 Spring");
    }
    
    // 국제화 파일 선택 1
    @Test
    void defaultLang() {
        assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
        assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
    }
    
    // 국제화 파일 선택 2
    @Test
    void enLang() {
        assertThat(ms.getMessage("hello", null, Locale.UK)).isEqualTo("hello");
        // messages.proerties KEY명, object 배열 null, locale english
        
    }
}

 

4.  웹 어플리케이션에 메시지 적용

  • messages 파일 생성
# 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=취소

 

  • 타임리프
<!--/*--> 
thymeleaf 사용 
#{basenames.key}
<!--*/-->

<h2 th:text="#{page.addItem}">상품 등록</h2>
<label for="itemName" th:text="#{label.item.itemName}">상품명</label>
<label for="price" th:text="#{label.item.price}">가격</label>
<label for="quantity" th:text="#{label.item.quantity}">수량</label>
<button class="w-100 btn btn-primary btn-lg" type="submit" th:text="#{button.save}">저장</button>

 

5.  웹 어플리케이션에서 국제화 적용

  • messages 국제화
# 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

 

  1. web Browser 언어 설정 -> 우선순위변경 
    • request Accept-Language의 값이 변경됨

  2. LocaleResolver 이용
    • 쿠키, 세션 등에 local 방식을 변경하도록 하는 방법 
    • 블로그보면 언어선택할 수 있는 란
    • 스프링이 제공하는 인터페이스
    • LocaleResolver 변경 - 쿠키나 세션 기반의 locale 선택 기능을 사용할 수 있다.
    • LocaleResolver 구글링하면 예제 많으니 필요시 사용
// LocaleResolver.Interface
public interface LocaleResolver {
    Locale resolveLocale(HttpServletRequest request);
    void setLocale(HttpServletRequest request, @Nullable HttpServletResponseresponse, @Nullable Locale locale);
}

 

  • LocalResolver 변경
    • 만약 Locale 선택 방식을 변경하려면 LocalResolver의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택기능을 사용할 수 있다.
    • 예) 고객인 직접 Locale을 선택하도록 한다.
    • LocaleResolver를 검색하면 수 많은 예제가 나오니 필요한 사람들을 참고