기능
- 사용자 선택에 따른 국제화 기능 구현
목적
- 다양한 LocaleResolver를 통한 메시지 및 국제화 기능 학습
프로젝트 환경 설정
- 의존관계 설정
- 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은 등록되어 있는 LocaleResolver의 resolverLocale() 메서드를 호출해서 사용할 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라고 한 이유는 select의 option값을 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;
}
SessionLocaleResolver의 LOCALE_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>
사용 언어를 선택하고 전송 버튼을 누르면 LanguageController의 changeLocale(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