이번 글에서는 Spring Boot에서 다국어 기능을 properties 파일이 아닌 yaml 파일을 이용하여 적용을 해보겠다.

 

다국어 관련 Config 파일 작성.

yml YamlResourceBundle 클래스를 사용하기 위한 pom.xml 파일 혹은 build.gradle 파일에 의존성 추가.

# Maven
<dependency>
  <groupId>net.rakugakibox.util</groupId>
  <artifactId>yaml-resource-bundle</artifactId>
  <version>1.1</version>
</dependency>

# gradle
implementation group: 'net.rakugakibox.util', name: 'yaml-resource-bundle', version: '1.1'

 

Config 클래스 생성

package com.blackvue.config;

import com.blackvue.common.interceptor.WebInterceptor;
import com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter;
import com.pittasoft.common.config.AFConfigYAML;
import net.rakugakibox.util.YamlResourceBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer{

	/**
	 * 변경된 언어 정보를 기억할 로케일 리졸버를 생성한다.
	 * 여기서는 세션에 저장하는 방식을 사용한다.
	 * @return
	 */
	@Bean
	public SessionLocaleResolver localeResolver() {
		SessionLocaleResolver localeResolver = new SessionLocaleResolver();
		localeResolver.setDefaultLocale(Locale.ENGLISH);
		return localeResolver;
	}

	/**
	 * 언어 변경을 위한 인터셉터를 생성한다.
	 */
	@Bean
	public LocaleChangeInterceptor localeChangeInterceptor() {
		LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
		interceptor.setParamName("lang");
		return interceptor;
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(localeChangeInterceptor())
				.excludePathPatterns("/resources/**", "/resources/", "/css/**", "/vendor/**", "/js/**", "/script/**", "/images/**", "/fonts/**", "/lib/**");
	}

	/**
	 * 각 언어별 메시지 정보를 yaml-bundle을 통해 가져옴
	 */
	@Bean("messageSource")
	public MessageSource messageSource(@Value("${spring.config.messages.basename}") String basename, 
    					@Value("${spring.config.messages.encoding}") String encoding ) {

		YamlMessageSource source = new YamlMessageSource();
		source.setBasename(basename);
		source.setDefaultEncoding(encoding);
		source.setAlwaysUseMessageFormat(true);
		source.setUseCodeAsDefaultMessage(true);
		source.setFallbackToSystemLocale(false);
		return source;
	}

}

class YamlMessageSource extends ResourceBundleMessageSource {
	@Override
	protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
		return ResourceBundle.getBundle(basename, locale, YamlResourceBundle.Control.INSTANCE);
	}
}

 

src/main/resources/appilcation.yml 에 다국어 설정파일이 있는 경로 추가.

spring:
  config:
    messages:
      basename: lang/messages
      encoding: UTF-8

 

 

src/main/resources/i18n/messages.yml 파일

alert:
  confirm: "확인"
  cancel: "취소"
  loginEmail: "아이디(이메일)를 입력해 주세요."
  loginPassword: "비밀번호를 입력해 주세요."
  loginFail: "아아디(이메일) 또는 비밀번호가 올바르지 않습니다."

src/main/resources/i18n/messages_en.yml 파일

alert: 
  confirm: "Ok" 
  cancel: "Cancel" 
  loginEmail: "Please enter your ID(Email)." 
  loginPassword: "Please enter a password." 
  loginFail: "The email or password is invalid."

src/main/resources/i18n/messages_jp.yml 파일

alert: 
  confirm: "确认" 
  cancel: "取消" 
  loginEmail: "请输入用户名(邮箱)。" 
  loginPassword: "请输入密码。" 
  loginFail: "请重新确认用户名(邮箱)或者密码。"

src/main/resources/i18n/messages_zh.yml 파일.

alert: 
  confirm: "確認" 
  cancel: "取り消し" 
  loginEmail: "ID(Eメール)を入力してください" 
  loginPassword: "パスワードを入力してください" 
  loginFail: "ID(Eメール)またはパスワードをもう一度ご確認ください。"

 

웹페이지에서 사용하기

<!-- Jsp -->
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <-- 태그 선언 후 

<spring:message code="alert.loginEmail" />

<!-- thymeleaf -->
1. <span th:text="#{alert.loginEmail}">아이디(이메일)를 입력해 주세요.</span>
2. <span>[[#{alert.loginEmail}]]</span>

default url 조회

영문조회 시 (lang=en)

일문 조회시 (lang=jp)

'Framework > Spring Boot' 카테고리의 다른 글

[Spring boot] 다국어 처리하기  (0) 2021.01.05

1. MessageSource

국제화 서비스를 위해서는 사용자 언어에 맞는 페이지가 번역되어 보여져야 합니다.

그런데 서비스 되는 언어마다 html 파일을 작성하여, 요청 언어에 따라 응답 페이지를 분기시키는 것은 매우 비효율적이고, 유지보수를 어렵게 만듭니다.

  • ko : index_ko.html
  • jp : index_jp.html
  • cn : index_cn.html
  • en : index_en.html
  • ...

 

그래서 하나의 템플릿만 만들어 놓고 다국어가 처리된 파일을 작성해주면, SpringBoot가 알아서 텍스트를 다국어 처리 할 수 있게끔 해주는 것이 MessageSource입니다.

즉, SpringBoot에서는 src/main/resources/messages.properties를 찾았을 때 자동으로 MessageSource를 구성하고,

해당 파일에 다국어를 작성해주기만 하면, SpringBoot가 알아서 사용자 언어를 확인한 후 메시지를 변환해줍니다.

 

 

2. 구현하기

프로젝트 구조

 

 

 

1) 컨트롤러

src/main/java/com/victolee/i18n/controller/i18nController.java

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class i18nController {

  @GetMapping("/test")
  public String test() {
  	return "test";
  }
}

 

 

2) 템플릿

src/main/resources/templates/test.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>i18n 테스트</h1>

  <p th:text="#{product}"></p>
  <p th:text="#{product.category}"></p>
</body>
</html>

thymeleaf에서 MessageSource의 메시지를 가져오기 위해서는 #{속성명}을 작성해주면 됩니다.

즉, product, product.category는 messages.properties 파일에서 언어별로 텍스트를 정의해줄 것입니다.

 

 

3) messages.properties

다음으로 messages_{언어코드}_{국가코드}.properties 파일에 번역 텍스트를 작성해줍니다.

messages.properties 파일은 사용자 언어 환경에 맞는 properties 파일이 없을 경우, 기본 값으로 보여지는 파일입니다.

 

 

각 properties 파일에서 텍스트를 작성하기 전에 IDE에서 *.properties 파일의 인코딩을 UTF-8로 설정해주도록 합니다.

그렇지 않으면 한글 등의 문자가 깨짐 현상이 발생합니다.

 

 

src/main/resources/messages.properties

product=some product
product.category=some category

src/main/resources/messages_en_US.properties

product=us product
product.category=us category

src/main/resources/messages_ko_KR.properties

product=한국 상품
product.category=한국 카테고리

 

각각의 파일은 이렇게 bundle로 묶여지면 손쉽게 관리할 수도 있습니다.

 

여담이지만.. properties 파일이 아닌 yml을 사용하고 싶은데, 현재 다른 포맷을 지원하고 있지 않다고 합니다. ( 참고 )

 

 

 

 

4) application.java

src/main/java/com/victolee/i18n/I18nApplicationjava

package com.victolee.i18n;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

@SpringBootApplication
public class I18nApplication {

  public static void main(String[] args) {
  	SpringApplication.run(I18nApplication.class, args);
  }

  /*
  * 사용자 언어 환경을 설정해주기 위한 bean 설정
  */
  @Bean
  public LocaleResolver localeResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    sessionLocaleResolver.setDefaultLocale(Locale.US); // <---- 해당 값을 수정하여 언어 결정
    return sessionLocaleResolver;
  }
}

테스트를 하려면 사용자 언어 환경을 셋팅해줘야 하기 때문에 bean을 추가합니다.

즉, Locale.US로 설정했으면 messages_en_US.properties에 작성된 텍스트가 보여집니다.

아래의 테스트는 해당 값을 바꿔가며 진행됩니다.

 

 

5) 테스트

Locale.US로 설정

messages_en_US.properties 파일에 명시된 텍스트가 의도된대로 노출됩니다.

 

 

 

Locale.JAPAN로 설정

messages_ja_JP.properties 파일은 작성하지 않았기 때문에, 기본 값인 messages.properties 파일의 텍스트가 보여질 것이라 예상할 수 있습니다.

그러나 messages_ko_KR.properties 텍스트가 노출되었는데, 이는 spring.messages.fallback-to-system-locale 설정과 관련이 있습니다.

기본 값이 false이므로 messages_ja_JP.properties 파일을 찾지 못했을 경우, 시스템의 locale을 따라가게 됩니다.

즉, messages_ko_KR.properties 에서 텍스트를 가져오는 것이죠.

( 설정에 대한 내용은 뒤에서 다루겠습니다. )

 

같은 상황에서 spring.messages.fallback-to-system-locale = false 를 해주면 아래와 같이 messages.properties에서 텍스트를 가져옵니다.

 

 

 

6) 설정

예제에서는 다루지 않았지만, MessageSource와 관련된 설정들을 application.yml 파일에 작성할 수 있습니다. ( 참고 )

 key

기본값 

 설명

 spring.messages.always-use-message-format

 false

 MessasgeFormat을 전체 메시지에 적용할 것인지 여부

 spring.messages.basename

 messages

 message 파일을 여러개 사용할 경우 콤마로 구분해서 여러개의 basename을 설정할 수 있다.

 spring.messages.cache-duration

 

 캐시 주기 설정, 기본 값 forever

 spring.messages.encoding

 UTF-8

 인코딩 방식

 spring.messages.fallback-to-system-locale

 true

 감지된 locale에 대한 파일이 없는 경우,

  • 설정값 true : system locale 사용
  • 설정값 false : messages.properties 파일을 사용
 spring.messages.use-code-as-default-message  false

 메시지를 찾지 못했을 때, 예외 처리 대신 메시지 코드를 그대로 반환

 

 

'Framework > Spring Boot' 카테고리의 다른 글

[Spring Boot] yaml로 다국어 기능 구현하기  (0) 2021.01.12

저번 글에서 Apache Camel을 이용을 하면 소스가 대폭 줄어든다고 했었는데 (https://nuji-94.tistory.com/12)

이번 글에선 예제를 통해 순수JAVA와 Camel의 소스를 비교해보겠다.

 

 

경로 C;/dev/logqueue/camel-exam 에 존재하는 camel-exam.txt 라는 파일의 내용을 읽어 Console창에 출력하여라. 라는 예제를 구현해보겠다.

 

먼저, 해당 경로에 camel-exam.txt 파일을 만든 후

위의 사진과 같이 파 일 읽 기 라는 내용을 넣었다.

 

 

순수 JAVA 소스로 파일의 내용을 읽는 소스는 다음과 같다.



 

-------------------------------------------------------------------------

 

다음은 Camel을 이용한 소스이다.



 

환경을 구성하기 번거롭다는 단점이 있기는 하지만

 

구현을 해놓으면 훨씬 더 간편하다. (글쓴이만의 생각 일 수도 있다ㅠ)

 

어떤가, 자네 Camel 한번 해보지 않겠는가?

 

 

 

'Framework > Apache Camel' 카테고리의 다른 글

[Apache Camel] Apache Camel 이란?  (0) 2021.01.05

Apache Camel

Apache Camel Home Page - http://camel.apache.org/

 

 

EIP(Enterprise Integration Pattern)에 기반한 open source Java framework

 

 

일반적으로 어플리케이션은 외부 I/F와 연동하기 위해 다양한 기술을 필요로 한다.

그림과 같이 일반 어플리케이션에서 외부 I/F와 연동하기 위해서는 각 I/F와 맞는 라이브러리나 API를 내장시키고, 시간을 들여 그에 맞는 기술을 익혀야 한다.

 

 

그에 반해, Apache Camel을 내장한 어플리케이션에서는 위의 그림과 같이 Camel을 통해 외부 I/F와 손쉽게 연동이 가능하다. 또한, Camel은 외부I/F와 연동을 위해 수백 가지 Component를 제공하고 있어 소스가 대폭 줄어들고, 그에 따라 개발 시간도 단축할 수 있다.

 

Apache Camel Component - http://camel.apache.org/components.html

 

Apache Camel 의 장점

1. JAVA 어플리케이션에 내장 가능한 경량 프레임워크

2. 어플리케이션의 내부에서 외부 I/F와 손쉽게 연동 할 수 있게 해줌

3. 많은 종류의 Camel-compornent를 이용하여 소스 대폭 감소 및 개발 시간 단축

 

Apache Camel 의 단점 (글쓴이 생각)

1. 초기 구축이 좀 복잡한 편이다.

2. 참고 자료 중 국내 자료가 거의 없는 편이다.(진입장벽이 높음)

 

 

감사합니다.

+ Recent posts