Extra edition) Multilingual processing

GEONNY·2024년 7월 29일

Building-API

목록 보기
10/28
post-thumbnail

응답 메시지의 다국어 처리에 대해서 알아보겠습니다.
한글을 default 로 설정하고 영어와 중국어를 추가해 보도록 하죠. IntelliJ의 Resource bundle 을 사용해 보겠습니다. 우선 기존의 message.properties 의 내용을 확인합니다.

SUCCESS.SEARCH.CODE=API_OK
SUCCESS.SEARCH.MESSAGE=데이터를 조회하는데 성공하였습니다.

내용 복사 후에 해당 파일을 삭제 합니다. (Resource Bundle 로 변경하는 법을 모르겠네요..😅)

📌Add 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_USzh_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 탭을 클릭하면 아래와 같이 해당 내용을 확인 할 수 있습니다.

📌Add message options

다음으로 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

📌Setting LocaleResolver

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);
    }
}

📌MessageConfig 구현

편의성을 위해 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());
    }
}

📌Controller 수정

위에서 생성한 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

i18nInternationalization 의 약어로, 제일 처음 문자 i 와 마지막 n 사이에 18 글자가 있다는 의미 입니다. 국제화 라는 단어인 Internationalization 를 사용하므로써 소프트웨어 어플리케이션을 여러 언어와 지역적 규칙을 지원하도록 설계하고 구현하는 과정을 의미하게 됩니다.
위에서 사용한 en_US 는 언어와 지역을 의미하며 영어_미국 을 의미 합니다. Locale을 찾는 우선순위로는 en_US 의 경우 message_en_US -> message_en -> message 순으로 찾게됩니다.

profile
Back-end developer

0개의 댓글