웹 개발/Back End
백엔드 다국어 처리
L3m0n S0ju
2025. 5. 31. 11:08
스프링에서 다국어 처리하는 법을 다뤄보겠습니다.
MessageSourceConfig.java
@Configuration
public class MessageSourceConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages/messages_common",
"classpath:messages/messages_core",
"classpath:messages/messages",
"classpath:messages/messages_notice",
"classpath:messages/messages_alarm");
messageSource.setDefaultEncoding("UTF-8");
// messageSource.setCacheSeconds(60); // 리로드 주기 설정 (초 단위, 0은 캐시 사용 안 함)
return messageSource;
}
}
- 최상위 모듈에 messageSource 함수를 @Bean으로 등록합니다.
########################################
공통(0 ~ 1999),
########################################
API-0000=입력값을 확인해주세요.
API-0001=로그인 정보가 없습니다.
API-0002=필수 입력값입니다.
API-0003=유효하지 않은 회사입니다.
API-0004=권한이 없습니다.
API-0005=전자결재를 상신 하려는 회사와 사용자의 소속 회사가 일치하지 않습니다.
API-0006=전자결재 드래프트를 그룹웨어에 전달 하였지만 실패 응답을 받았습니다.
API-0007=유효하지 않은 사용자입니다.
########################################
휴가 현황 message,
########################################
leave.other=외
leave.item=건
leave.granted.upon.request=신청 시 지급
leave.granted.upon.years.of.service={0}년 근속 시 지급
leave.every.year=매년 {0} 지급
leave.every.month=매월 {0}일 지급
leave.every.week=매주 {0} 지급
leave.direct.grant=직접 지급
leave.day=일
leave.half.day=반차
leave.quarter.day=반반차
leave.hour={0}시간
leave.minute={0}분
- 파일이름이 messages 인 경우 messages.properties는 기본 파일이고 messages_ko.properties, message_en.properties 등 파일을 만듭니다. 예외는 코드를 등록하고 일반 문장은 키 값을 넣어줍니다.
MessageCreator.java (일반적인 다국어 처리된 값 가져오기)
@Component
@RequiredArgsConstructor
public class MessageCreator {
private final MessageSource messageSource;
public final String getMessage(String key, String... params) {
return messageSource.getMessage(key, params, LocaleContextHolder.getLocale());
}
}
- 프론트에 GET /api/welcome?lang=ja 이런식으로 언어 정보를 넘겨주면 LocaleContextHolder.getLocale()을 통해서 언어 정보를 가져올 수 있다고 합니다. 따라서 메시지를 번역할 때는 위 코드처럼 messageCreator를 만들어서 사용하거나 바로 사용하거나 하면 됩니다.
파라미터가 있는 다국어 처리된 값 가져오기
@Component
@RequiredArgsConstructor
public class MessageUtils {
private final MessageSource messageSource;
public final String getMessageWithParams(String key, String... params) {
return messageSource.getMessage(key, params, LocaleContextHolder.getLocale());
}
public final String resolveLeaveDescription(String message) {
List<String> messageList = List.of(message.split(":"));
if (messageList.isEmpty()) {
return "";
}
String key = messageList.get(0);
String[] params = messageList.subList(1, messageList.size()).toArray(new String[0]);
return getMessageWithParams(key, params);
}
}
- DB에는 leave.every.month:7 이런식으로 저장되어 있으므로 가져와서 :를 기준으로 key와 params를 분리합니다. 그리고 마찬가지로 messageSource의 getMessage 함수를 사용하면 파라미터가 적용된 다국어 처리된 값을 가져올 수 있습니다.
StatusDescriptionService.java (DB에 값 저장하기)
@Slf4j
@Service
@RequiredArgsConstructor
public class StatusDescriptionService {
private final MessageUtils messageUtils;
public String getAnnualLeaveDescription(int yearsOfService) {
return ColonMessageBuilder.of("leave.annual.grant.year", yearsOfService);
}
public String getCustomLeaveRegularSchedulingYearly(LocalDate now) {
return ColonMessageBuilder.of("leave.custom.regular.scheduling.yearly", getMmDdString(now));
}
public String getCustomLeaveRegularSchedulingServiceYears(int year) {
return ColonMessageBuilder.of("leave.custom.regular.scheduling.service.years", year);
}
public String getExcelUpload(String monthDay) {
return ColonMessageBuilder.of("leave.annual.excel.upload", monthDay);
}
}
- DB에 값을 저장할 때는 아래와 같이 key와 파라미터에 포맷을 지정 후 저장합니다.
ColonMessageBuilder.java
public class ColonMessageBuilder {
public static String of(String key, Object... params) {
return Stream.concat(Stream.of(key), Arrays.stream(params))
.map(String::valueOf)
.collect(Collectors.joining(":"));
}
}
하지만 문제점이 있습니다. 파라미터 값은 꺼낼 때 다국어 처리가 안된다는 점입니다. 그래서 저장할 때 다국어 처리를 미리해서 넣어줘야하는데 이렇게 되면 해외에서 사이트에 들어가면 파라미터 부분은 DB에 저장할 당시의 값이 보이게 됩니다.
public String getTranslatedMessage(String colonString) {
String[] parts = colonString.split(":");
String key = parts[0];
Object[] params = Arrays.stream(parts)
.skip(1)
.map(param -> {
// 메시지 키처럼 생겼다면 번역 시도 (예: dayOfWeek.MONDAY)
if (param.matches("[a-zA-Z0-9_.]+")) {
try {
return messageSource.getMessage(param, null, LocaleContextHolder.getLocale());
} catch (NoSuchMessageException e) {
return param; // 메시지가 없으면 원본 사용
}
}
return param;
})
.toArray();
return messageSource.getMessage(key, params, LocaleContextHolder.getLocale());
}
만약에 파라미터 또한 무조건 다국어 처리를 해야한다면 위 코드처럼 하는 방법이 있다고 GPT가 알려주었습니다.