티스토리 뷰

🍀 Spring Boot

MessageSource-다국어 설정

James Wetzel 2025. 2. 6. 16:19
728x90
반응형

다국어(Internationalization, i18n)를 적용하기 위해서는 다음과 같은 단계로 진행할 수 있습니다. 아래는 단계별로 필요한 설정과 코드 예제를 제공합니다.


1. 메시지 프로퍼티 파일 생성

먼저, 기본 메시지 파일과 다국어에 대응하는 메시지 파일을 작성합니다.

예를 들어, 다음과 같이 메시지 파일들을 작성합니다.

 

src/main/resources/messages.properties (기본 언어 – 보통 영어)

user.email.exists=Email already exists.

 

src/main/resources/messages_ko.properties (한국어)

user.email.exists=이미 존재하는 이메일입니다.

필요에 따라 다른 언어의 파일도 추가할 수 있습니다.


2. MessageSource Bean 설정

Spring Boot에서 메시지 프로퍼티 파일들을 로드하기 위해 MessageSource 빈을 등록합니다. 일반적으로 @Configuration 클래스를 생성하여 설정합니다.

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

@Configuration
public class InternationalizationConfig {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        // classpath 하위의 messages*.properties 파일을 읽어옵니다.
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");
        // 기본 메시지를 찾지 못할 경우 예외 대신 코드 자체를 반환하도록 설정 가능
        messageSource.setUseCodeAsDefaultMessage(true);
        return messageSource;
    }
}

참고: Spring Boot의 기본 설정에서도 messages.properties를 자동으로 로드하지만, 커스터마이징이 필요한 경우 위와 같이 별도 설정하는 것이 좋습니다.


3. Controller에서 메시지 사용하기

컨트롤러에서는 MessageSource 빈을 주입받아, 요청 시점의 로케일(Locale)에 맞춰 메시지를 가져올 수 있습니다.

예를 들어, 회원가입 API에서 이메일 중복 시 다국어 메시지를 반환하는 코드는 아래와 같이 작성할 수 있습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Locale;
import java.util.Set;

@RestController
@Validated
public class UserController {

    private final UserService userService;
    private final PasswordEncoder passwordEncoder;
    private final MessageSource messageSource; // MessageSource 주입

    @Autowired
    public UserController(UserService userService, 
                          PasswordEncoder passwordEncoder,
                          MessageSource messageSource) {
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
        this.messageSource = messageSource;
    }

    @PostMapping("/signUp")
    public ResponseEntity<ApiResult<SignUpResponseDTO>> signUp(@RequestBody @Valid SignUpRequestDTO request) {
        // 이메일 중복 체크
        if (userService.existsByEmail(request.getEmail())) {
            // 현재 요청의 Locale 가져오기
            Locale locale = LocaleContextHolder.getLocale();
            // 메시지 코드에 해당하는 메시지를 다국어로 가져오기
            String errorMessage = messageSource.getMessage("user.email.exists", null, locale);
            return ResponseEntity.ok(new ApiResult<>(false, errorMessage, null));
        }

        // 신규 사용자 생성
        User user = User.builder()
                .email(request.getEmail())
                .password(passwordEncoder.encode(request.getPassword()))
                .roles(Set.of(User.UserRole.ROLE_USER))
                .build();

        SignUpResponseDTO response = new SignUpResponseDTO();
        response.setEmail(userService.save(user).getEmail());
        return ResponseEntity.ok(new ApiResult<>(true, ApiResult.MessageType.SUCCESS.name(), response));
    }
}

설명:

  • LocaleContextHolder.getLocale()를 사용하면 현재 요청에 설정된 로케일을 가져올 수 있습니다. (예: HTTP 요청의 Accept-Language 헤더 등을 기반으로 설정)
  • messageSource.getMessage("user.email.exists", null, locale)를 통해 해당 로케일에 맞는 메시지를 가져옵니다.

4. HTTP 요청 시 로케일 설정

클라이언트가 HTTP 요청 헤더의 Accept-Language 값을 통해 원하는 언어를 전달할 수 있습니다. 예를 들어, 클라이언트가 Accept-Language: ko 헤더를 보내면 LocaleContextHolder는 한국어 로케일(ko)를 가지게 되고, 이 경우 messages_ko.properties 파일에서 메시지를 읽어옵니다.

Spring Boot는 기본적으로 Accept-Language 헤더를 기반으로 로케일을 결정합니다. 추가적인 로케일 설정이 필요한 경우, 아래와 같이 LocaleResolver 빈을 등록할 수 있습니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

import java.util.Locale;

@Configuration
public class LocaleConfig {

    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
        resolver.setDefaultLocale(Locale.ENGLISH); // 기본 로케일 설정
        return resolver;
    }
}

결론

위와 같이 설정하면, 회원가입 컨트롤러에서 이메일 중복 시 user.email.exists 코드에 해당하는 메시지가 클라이언트의 로케일에 맞춰 반환됩니다.
이로써 "이미 존재하는 이메일입니다."와 같은 메시지를 다국어로 처리할 수 있습니다.

 

인텔리제이(intellij) 한국어 설정

Transparent native-to-ascii conversion을 체크합니다.

 

추가 사항(MessageProvider)

package com.example.demo.provider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;

@Component
public class MessageProvider {

    private static MessageSource messageSource;

    // MessageSource 빈을 주입받음 (비정적 필드)
    @Autowired
    private MessageSource autowiredMessageSource;

    // PostConstruct를 통해 정적 변수에 할당
    @PostConstruct
    public void init() {
        MessageProvider.messageSource = this.autowiredMessageSource;
    }

    /**
     * 주어진 메시지 코드와 인자에 대해 현재 요청의 Locale에 맞는 메시지를 반환합니다.
     *
     * @param code 메시지 코드 (예: "user.email.exists")
     * @param args 메시지 포맷에 사용할 인자 (필요하지 않은 경우 null)
     * @return 해당 로케일에 맞는 메시지 문자열
     */
    public static String getMessage(String code, Object[] args) {
        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
    }

    // 인자 없이 메시지 코드를 조회할 수 있도록 오버로드된 메서드
    public static String getMessage(String code) {
        return getMessage(code, null);
    }
}

 

// MessageProvider 호출
MessageProvider.getMessage("user.email.exists")

 

728x90
반응형