본문 바로가기
JAVA/Spring

메시지, 국제화 LocaleResolver 구현

by sihyeong 2023. 12. 5.

기능

  • 사용자 선택에 따른 국제화 기능 구현

목적

  • 다양한 LocaleResolver를 통한 메시지 및 국제화 기능 학습

프로젝트 환경 설정

https://start.spring.io/

 

  • 의존관계 설정
    • Thymeleaf
    • Lombok
    • Spring Web
  • Gradle
  • Java 8
  • Jar

국제화 기능 구현

스프링은 LocaleResolver 인터페이스를 통해 클라이언트의 언어 & 국가 정보를 인식한다. 스프링 MVC는 LocaleResolver로 웹 요청과 관련된 Locale 객체를 추출하여 알맞는 언어 메시지를 선택하게 된다.  

 

국제화는 메시지 기능을 토대로 구현할 수 있다. 메시지 기능을 구현하기 위한 파일을 먼저 생성한다. 파일명은 스프링 부트가 기본으로 제공하는 messages사용한다.

 

이에 대한 기본 지식이 부족한 분은 아래의 게시글을 확인해보길 바란다.

https://coding-chronicle.tistory.com/106

 

메시지, 국제화

메시지 만약 화면에 보이는 문구인 상품명이라는 단어를 모두 상품이름으로 변경하고자 한다면 어떻게 해야 할까? 상품명이 적힌 화면들을 다 찾아가면서 모두 변경해야 한다. 만약 해당 화면

coding-chronicle.tistory.com

 

생성한 국가별 메시지 properties 파일

src/resources/messages.properties 와 기타 국가의 properties를 생성

🔴 application.properties

스프링 부트는 자동으로 LocaleResolver를 등록하고 관련 설정을 해준다.

다루게 될 메시지 파일의 이름(기본 messages)와 인코딩 (기본 UTF-8)를 application.properties에 작성한다. 이 둘은 기본값이라 생략해도 무방하다.

spring.messages.basename=messages
spring.messages.encoding=UTF-8

 

🔴 messages.properties

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

title=메시지, 국제화 테스트
subtitle=스프링

label.select=언어 선택

option.select=== 언어 선택 ==
option.lang.ko=한국어
option.lang.en=영어
option.lang.ja=일본어

button.submit=전송

 

기본 메시지 파일이다. 한국어를 기본 메시지 파일로 설정했고, 메시지는 ke와 value 형태로 사용한다.

 

🔴 messages_en.properties

hello=hello
hello.name=hello {0}

title=message, i18n test
subtitle=spring

label.select=select language

option.select=== select language ==
option.lang.ko=Korean
option.lang.en=English
option.lang.ja=Japanese

button.submit=submit

🔴 messages_ja.properties

hello=こんにちは
hello.name=こんにちは {0}

title=メッセージ、国際化テスト
subtitle=春

label.select=言語を選択

option.select=== 言語を選択 ==
option.lang.ko=韓国語
option.lang.en=英語
option.lang.ja=日本語

button.submit=転送

 

 

🔴 LocaleResolver 인터페이스

public interface LocaleResolver {

	/**
	 * Resolve the current locale via the given request.
	 * Can return a default locale as fallback in any case.
	 * @param request the request to resolve the locale for
	 * @return the current locale (never {@code null})
	 */
	Locale resolveLocale(HttpServletRequest request);

	/**
	 * Set the current locale to the given one.
	 * @param request the request to be used for locale modification
	 * @param response the response to be used for locale modification
	 * @param locale the new locale, or {@code null} to clear the locale
	 * @throws UnsupportedOperationException if the LocaleResolver
	 * implementation does not support dynamic changing of the locale
	 */
	void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);

}

 

먼저 LocaleResolver에 대해 알아보자

- resolveLocale() 메서드는 요청에 관련된 Locale을 리턴한다. DispatcherServlet은 등록되어 있는 LocaleResolverresolverLocale() 메서드를 호출해서 사용할 Locale을 구한뒤 Locale에 맞게 웹 요청을 처리한다.

 

 스프링은 LocaleResolver 인터페이스의 다양한 구현체를 제공한다.

클래스 설명
AcceptHeaderLocaleResolver 웹 브라우저가 전송한 헤더의 Accept-Language 값을 기반으로 Locale을 선택한다. setLocale() 메서드를 지원하지 않는다.
SessionLocaleResolver 세션으로부터 Locale 정보를 구한다.
setLocale() 메서드는 세션에 Locale 정보를 저장한다.
CookieLocaleResolver 쿠키를 이용해서 Locale 정보를 구한다.
setLocale() 메서드는 쿠키에 Locale 정보를 저장한다.
FixedLocaleResolver 웹 요청에 상관없이 특정한 Locale로 설정한다.
setLocale() 메서드를 지원하지 않는다.

 

참고로 LocaleResolver를 직접 스프링 빈으로 등록할 경우 빈의 이름을 localeResolver로 등록해야 한다.

그리고 LocaleResolver의 구현체가 어떤 것이냐에 따라서 Locale 지정 방식이 달라진다.


1. SessionLocaleResolver를 스프링 빈에 등록

🔴 WebConfig

@Configuration
public class WebConfig {

    @Bean
    public LocaleResolver localeResolver() {
        return new SessionLocaleResolver();
    }
}

 

 

2. 컨트롤러에서 세션 값 처리

🔴 Language

select 형식으로 언어를 선택하여 변경 버튼을 누르면 해당 페이지들이 선택한 언어에 맞게 Locale 값이 변경되도록 할 것이다. select 안에 들어갈 값들을 동적으로 출력하기 위해 enum으로 정의한다.

 

lang값을 ko, en, ja라고 한 이유는 selectoption값을 lang값으로 해당 언어가 나오도록 설정하기 위함이다.

@Getter
public enum Language {
    KOREA("ko", Locale.KOREA),
    ENGLISH("en", Locale.ENGLISH),
    JAPAN("ja", Locale.JAPAN);

    private String lang;
    private Locale locale;

    Language(String lang, Locale locale) {
        this.lang = lang;
        this.locale = locale;
    }
}

 

🔴 LanguageController

@Controller
@RequiredArgsConstructor
@Slf4j
public class LanguageController {

    @GetMapping
    public String home(@ModelAttribute LanguageDto languageDto, Model model) {
        model.addAttribute("languages", Language.values());
        return "/home";
    }

    @PostMapping
    public String changeLocale(@ModelAttribute LanguageDto languageDto, HttpSession session) {
        log.info(languageDto.toString());
        Locale locale = languageDto.getLocale();
        session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
        return "redirect:/";
    }

}

 

뷰에서 사용자가 변경할 언어를 선택해서 전송하면 languageDto가 해당 정보를 받고 

languageDto.getLocalte()을 통해 값을 가져와서

session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale) 를 통해 세션에 locale 정보를 지정하여 언어를 변경하게 된다.

 

localeResolver의 구현체로 SessionLocaleResolver를 등록시켰기 때문에 세션값을 토대로 언어가 변경된다.

 

🔴 SessionLocaleResolver

public class SessionLocaleResolver extends AbstractLocaleContextResolver {

	public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE";

	private String localeAttributeName = LOCALE_SESSION_ATTRIBUTE_NAME;

	public void setLocaleAttributeName(String localeAttributeName) {
		this.localeAttributeName = localeAttributeName;
	}

 

SessionLocaleResolverLOCALE_SESSION_NAME세션의 키값으로 사용되며 이 키값을 통해 사용 언어를 구분한다.

 

2. 뷰 작업

🔴 home.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1 th:text="#{title}">메시지, 국제화 테스트</h1>
<h2 th:text="#{hello.name(#{subtitle})}"></h2>
<form method="post" th:object="${languageDto}">
    <div th:text="#{label.select}">== 언어 선택 ==</div>
    <select th:field="*{locale}">
        <option value="" th:text="#{option.select}">언어 선택</option>
        <option th:each="language : ${languages}" th:with="lang=|option.lang.${language.lang}|"
                th:value="${language.locale}" th:text="#{${lang}}"></option>
    </select>

    <button type="submit" th:text="#{button.submit}">전송</button>
</form>

</body>
</html>

 

사용 언어를 선택하고 전송 버튼을 누르면  LanguageControllerchangeLocale(LanguageDto languageDto)locale 정보를 받아 세션에 locale을 등록하여 사용 언어를 바꾼다.

 

 <option th:each="language : ${languages}" th:with="lang=|option.lang.${language.lang}|"
                th:value="${language.locale}" th:text="#{${lang}}"></option>

 

language enum값으로 반복을 돌며 value text를 세팅하게 된다. 이때 언어에 맞는 text값을 출력하기 위해 th:with를 통해 properties의 키값을 변수로 뽑은다음 해당 변수를 통해 메시지 조회하여 텍스트를 구성하도록 만들었다.


실행결과 (기본값, 한국어):

실행결과 (영어):

실행결과 (일본어):


SessionLocaleResolver외에도 CookieLocaleResolver나 기타 LoacleResolver를 통해 국제화를 구현할 수 있습니다.

 

 

꼭 국제화가 아니더라도 이 기능을 활용해 복잡한 무언가의 값을 관리하거나 변경할 때 사용하면 도움이 될 것 같습니다.

 

 

👀 참고자료

https://terry9611.tistory.com/304

 

[Spring] 기본 메시지 기능 V2 - 다양한 LocaleResolver 구현을 통한 국제화 기능 구현

더보기 public interface LocaleResolver { /** * Resolve the current locale via the given request. * Can return a default locale as fallback in any case. * @param request the request to resolve the locale for * @return the current locale (never {@code nul

terry9611.tistory.com

 

'JAVA > Spring' 카테고리의 다른 글

메시지, 국제화  (0) 2023.12.04