
응답 메시지의 다국어 처리에 대해서 알아보겠습니다.
한글을 default 로 설정하고 영어와 중국어를 추가해 보도록 하죠. IntelliJ의 Resource bundle 을 사용해 보겠습니다. 우선 기존의 message.properties 의 내용을 확인합니다.
SUCCESS.SEARCH.CODE=API_OK
SUCCESS.SEARCH.MESSAGE=데이터를 조회하는데 성공하였습니다.
내용 복사 후에 해당 파일을 삭제 합니다. (Resource Bundle 로 변경하는 법을 모르겠네요..😅)

그리고 messages 폴더에서 오른쪽 버튼을 클릭하고 New > Resource Bundle 을 선택합니다.
Create Resource Bundle 팝업창이 뜨면 Resource bundle base name 을message 로 입력 하고 Locales to Add 버튼을 눌러 en_US (영어/미국)와 zh_CN (중국어/중국) 을 추가합니다.

OK 버튼을 클릭하면 총 3개의 파일이 생성됩니다.

Add Files to Git 팝업이 나오면 모두 선택을 하고 Add 버튼을 클릭합니다.
이제 기존에 message.properties의 내용을 새로 생성한 파일에 붙여넣습니다. 그리고 en_US 와 zh_CN 파일도 번역하여 입력합니다.
message_en_US.properties
SUCCESS.SEARCH.CODE=API_OK
SUCCESS.SEARCH.MESSAGE=Data retrieved successfully.
message_zn_CN.properties
SUCCESS.SEARCH.CODE=API_OK
SUCCESS.SEARCH.MESSAGE=数据检索成功.
(번역기를 돌린거라 내용이 맞지 않을 수 있습니다.🤫)
message.properties 파일 하단의 Resource Bundle 탭을 클릭하면 아래와 같이 해당 내용을 확인 할 수 있습니다.

다음으로 application.yml 에 messages 관련 설정을 합니다. base 경로와 인코딩, 캐시 기간 등을 설정합니다.
spring:
messages:
basename: messages/message
encoding: UTF-8
cache-duration: 30
always-use-message-format: true
use-code-as-default-message: true
fallback-to-system-locale: true
Header 의 Accept-Languaget 값을 기반으로 Locale을 설정하기 위해 LocaleResolver 를 설정합니다. Default 를 Locale.KOREA 로, Header 에 Accept-Language 가 있을 경우 해당 값으로 설정되게 합니다.
config.locale.LocaleConfig

@Configuration
public class LocaleConfig extends AcceptHeaderLocaleResolver {
@Bean
public LocaleResolver localeResolver() {
AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
resolver.setDefaultLocale(Locale.KOREA);
return resolver;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
String acceptLanguage = request.getHeader("Accept-Language");
return (StringUtils.isEmpty(acceptLanguage))
? Locale.getDefault()
: Locale.forLanguageTag(acceptLanguage);
}
}
편의성을 위해 message를 Locale 에 따라 조회하는 bean을 등록합니다.
config.message.MessageConfig
@Configuration
@RequiredArgsConstructor
public class MessageConfig {
private final MessageSource messageSource;
private String getMessage(String code) {
return messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
}
}
위에서 생성한 getMessage method로 message 처리를 위해 Controller 를 수정합니다.
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
private final MessageConfig messageConfig;
@GetMapping(value = "/members/{memberId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ItemResponse<MemberSearchResponse>> getMemberById(
@PathVariable("memberId") String memberId) {
return ResponseEntity.ok()
.body(ItemResponse.<MemberSearchResponse>builder()
.status(messageConfig.getMessage("SUCCESS.SEARCH.CODE"))
.message(messageConfig.getMessage("SUCCESS.SEARCH.MESSAGE"))
.item(memberService.getMemberById(memberId))
.build());
}
@GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ItemsResponse<MemberSearchResponse>> getMembers() {
return ResponseEntity.ok()
.body(ItemsResponse.<MemberSearchResponse>builder()
.status(messageConfig.getMessage("SUCCESS.SEARCH.CODE"))
.message(messageConfig.getMessage("SUCCESS.SEARCH.MESSAGE"))
.items(memberService.getMembers())
.build());
}
}
이제 Locale 이 정확히 동작하는지 확인하기 위해 Chrome 의 설정을 변경합니다.
우측 상단 메뉴 버튼을 클릭하고 설정 메뉴를 엽니다. 설정에서 언어를 선택하고 영어를 가장위로 변경하여 http://localhost:13713/my-api/members/member1 API를 요청해 봅니다.

{
status: "API_OK",
message: "Data retrieved successfully.",
item: {
memberId: "member1",
memberName: "회원 명"
}
}
중국어(간체) 를 가장 위로 설정하여 API 를 다시 요청해봅니다.
{
status: "API_OK",
message: "数据检索成功.",
item: {
memberId: "member1",
memberName: "회원 명"
}
}
크롬 언어 우선순위에 따라 Request Headers 의 Accept-Language 가 변경되어 설정에 맞는 message가 전달되는 것을 확인하실 수 있습니다.😁
i18n 은 Internationalization 의 약어로, 제일 처음 문자 i 와 마지막 n 사이에 18 글자가 있다는 의미 입니다. 국제화 라는 단어인 Internationalization 를 사용하므로써 소프트웨어 어플리케이션을 여러 언어와 지역적 규칙을 지원하도록 설계하고 구현하는 과정을 의미하게 됩니다.
위에서 사용한 en_US 는 언어와 지역을 의미하며 영어_미국 을 의미 합니다. Locale을 찾는 우선순위로는 en_US 의 경우 message_en_US -> message_en -> message 순으로 찾게됩니다.