메세지,국제화

이정원·2024년 11월 4일
post-thumbnail

1.메세지 개요

악덕 기획자가 화면에 표시된 문구가 마음에 들지 않아, "상품명"이라는 단어를 모두 "상품이름"으로 수정해달라고 요청했다고 가정해 보자. 이 경우, 여러 화면에 걸쳐 표시된 "상품명", "가격", "수량" 등의 레이블을 일일이 찾아가면서 변경해야 한다. 현재는 페이지가 적어 큰 문제가 되지 않지만, 만약 페이지가 수십 개 이상이라면 수많은 파일을 모두 수정해야 하는 상황이 발생할 수 있다.

원인은 HTML 파일에 메세지가 하드코딩 되어있기 때문이다.

<!-- 주석 표시한 부분이 메세지가 들어갈 자리-->

 <form action="item.html" th:action th:object="${item}" method="post">
        <div>
          <label for="itemName">**<!--상품명--></label>
            <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
        </div>
        <div>
            <label for="price"><!--가격--></label>
            <input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요">
        </div>
        <div>
            <label for="quantity"><!--수량--></label>
            <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
        </div>

        <hr class="my-4">

이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다. messages.properties라는 메시지 관리용 파일을 만들고

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

addForm.html

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

editForm.html

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

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

국제화 개요

메시지에서 설명한 메시지 파일(messages.properties)을 각 나라별로 별도로 관리하면 국제화를 통해 애플리케이션에서 다국어 메시지를 지원하고, 사용자가 설정한 언어 및 문화권에 맞는 텍스트를 표시할 수 있다.

messages.properties 국제화 예시

한국

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

미국

item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity

HTTP accept-language 헤더 값을 사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리한다.

3.MessageSource

스프링 부트를 사용하면 스프링 부트가 MessageSource를 자동으로 스프링 빈으로 등록한다. src/main/resources 경로에 messages.properties, messages_en.properties, messages_ko.properties 등의 파일이 있으면, Spring Boot는 자동으로 해당 파일들을 찾아서 국제화 메시지를 처리한다

3-1.MessageSource 소스 설정

messages.properties(default)

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

messages_en.properties

hello=hello
hello.name=hello {0}

3-2.MessageSource 사용

메세지 소스를 포함하고 있는 MessageSource가 스프링 빈에 등록되어 사용 가능하다.

Test 코드

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

    @Test
    void helloMessage(){
        String hello = ms.getMessage("hello", null, null);
        Assertions.assertThat(hello).isEqualTo("안녕");
    }
}

locale(3번째 argument)이 null이면 default인 messages.properties파일의 key 값을 불러온다.

만약 메세지를 읽지 못하는 에러가 발생한다면 아래와 같이 설정을 UTF-8로 변경한다.

3-2-1. notFoundMessageCode

@Test
    void notFoundMessageCode() {
        Assertions.assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
                .isInstanceOf(NoSuchMessageException.class);
    }

ms.getMessage("no_code", null, null)를 호출할 때 no_code라는 메시지 키가 존재하지 않아 NoSuchMessageException이 발생한다.

@Test
    void notFoundMessageCodeDefaultMessage() {
        String result = ms.getMessage("no_code", null, "기본 메시지", null);
        Assertions.assertThat(result).isEqualTo("기본 메시지");
    }

ms.getMessage("no_code", null, "기본 메시지", null)를 호출할 때 no_code라는 메시지 키가 존재하지 않으면 "기본 메시지"가 반환된다.

3-2-2. argumentMessage

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

messages.properties에 hello.name=안녕 {0} 으로 설정되어 있기 때문에 argument "Spring"을 hello.name에 넘긴다면 "안녕 Spring"을 반환한다.

3-2-3. 국제화 Test

 @Test
 void defaultLang() {
 assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕");
 assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
}

@Test
    void enLang() {
        Assertions.assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
    }

나라별 함수를 작성하여 테스트 해보면 정상적으로 통과한다.

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

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

messages.properties에 해당 내용을 추가하고 타임리프의 메시지 표현식 #{...}를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다.

렌더링 전

<div th:text="#{label.item}"></h2>

렌더링 후

<div>상품</h2>

5.국제화 적용

messages_en.properties에 내용을 추가하고 Chrome 설정-> 언어 검색 -> 영어(가장 위로 이동) -> 새로고침 으로 언어를 영어로 변경하여 메세지가 잘 적용됬는지 확인한다.

스프링의 국제화 메세지 선택

스프링은 언어 선택시 기본으로 Accept-Language 헤더의 값을 사용하여 브라우저의 설정에 따라 LocaleResolver가 적절한 Locale을 설정한다.

0개의 댓글