๋ฉ์์ง
์ํฉ์ ํ๋ ๊ฐ์ ํด์, ๊ฒ์ํ ์๋น์ค๋ฅผ ๋ง๋ค์๋ค๊ณ ์๊ฐํ์.
๋ชจ๋ ๊ฒ์ํ์์ ๊ฒ์ํ์ ๋ฌ๋ฆฐ ๊ธ์ "๋๊ธ"์ด๋ผ๊ณ ํ์ํ๋ค๊ณ ์๊ฐํด๋ณด์.
๊ทธ ์ํฉ์์ ๋๊ธ์ "๋ต๊ธ"๋ก ๊ณ ์น๋ผ๋ ๋ช ๋ น์ด ๋จ์ด์ก๋ค๊ณ ์๊ฐํด๋ณด์.
์ฐ๋ฆฌ๋ ๋ชจ๋ ํ์ด์ง์ ๋๊ธ์ ์ฐพ์ ๋ต๊ธ๋ก ๊ณ ์ณ์ผ ํ ๊ฒ์ด๋ค.
ํ๋ฉด์ด ๋ง์ผ๋ฉด ๋ง์์๋ก ํด๋น ์์ ์ ํ๋ค๊ณ , ๋๋ฝํ ๊ฐ๋ฅ์ฑ๋ ์กด์ฌํ ๊ฒ์ด๋ค.
์ด๋ฐ ๋ค์ํ ๋ฉ์์ง๋ฅผ ํ ๊ณณ์์ ๊ด๋ฆฌํ๋๋ก ํ๋ ๊ธฐ๋ฅ์ ๋ฉ์์ง ๊ธฐ๋ฅ์ด๋ผ ํ๋ค.
์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
'messages.properties'๋ผ๋ ๋ฉ์์ง ๊ด๋ฆฌ์ฉ ํ์ผ์ ๋ง๋ค๊ณ
comment=๋ต๊ธ
comment.writer=์์ฑ์
...
์์๊ฐ์ด ์์ฑํ ํ, ๊ฐ HTML(ํ์๋ฆฌํ)๋ค์ ๋ค์๊ณผ ๊ฐ์ด ํด๋น ๋ฐ์ดํฐ๋ฅผ key๊ฐ์ผ๋ก ๋ถ๋ฌ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
(์ด๋ ๋ทฐ ํ ํ๋ฆฟ ๋ฟ๋ง ์๋๋ผ, Rest API์ ์๋ต์ผ๋ก๋ ์ ์ฉํ์ฌ ์ฌ์ฉํ ์ ์๋ค)
๊ตญ์ ํ
๋ฉ์์ง์์ ์กฐ๊ธ๋ง ๋ ๋์๊ฐ๋ณธ๋ค๋ฉด, ํด๋น ๋ฉ์์ง๋ค์ ๊ตญ๊ฐ๋ณ๋ก ๊ด๋ฆฌํจ์ผ๋ก์จ ์๋น์ค๋ฅผ ๊ตญ์ ํ ํ ์ ์๋ค.
์๋ฅผ ๋ค์ด ๋๊ธ์, ์์ด๋ฅผ ์ฐ๋ ๋๋ผ์์๋ comment๋ผ๊ณ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ด๋ค.
์ด๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตญ๊ฐ๋ณ ํ์ผ์ ๋ง๋ค์ด์ ๋ฉ์์ง๋ฅผ ๊ด๋ฆฌํจ์ผ๋ก์จ ๊ฐ๋ฅํด์ง๋ค.
messages_en.properties
comment=comment
comment.writer=Writer
...
messages_ko.properties
comment=๋ต๊ธ
comment.writer=์์ฑ์
...
๊ทธ๋ฆฌ๊ณ ํด๋น ๋ฉ์์ง์ ๊ตญ์ ํ ๊ธฐ๋ฅ์ ์คํ๋ง์์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ์ ๊ณตํ๋ค.
์คํ๋ง์์ ์ ๊ณตํ๋ ๋ฉ์์ง์ ๊ตญ์ ํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๋ฒ์ ์์๋ณด์.
์คํ๋ง์์ ์ ๊ณตํ๋ ๋ฉ์์ง ๊ธฐ๋ฅ
์คํ๋ง์์ ๋ฉ์์ง ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด, ์คํ๋ง์ด ์ ๊ณตํ๋ MessageSource๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํด์ผ ํ๋ค. MessageSource๋ ์ธํฐํ์ด์ค์ด๊ณ , ๊ตฌํ์ฒด์ธ ResourceBundleMessageSource๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํด์ฃผ์ด์ผ ํ๋ค.
๊ทธ๋ฌ๋ ์คํ๋ง๋ถํธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์๋์ผ๋ก ๋ฑ๋กํด์ฃผ๊ธฐ ๋๋ฌธ์, ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค.
์คํ๋ง๋ถํธ์์ ๋ฉ์์ง ์์ค ์ค์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
application.properties
spring.messages.basename=messages, config.messages
config.messages๋ config ํด๋ ์๋์ ์์นํ๋ messages๋ผ๋ ๋ป์ด๋ค.
(default๊ฐ์ messages์ด๋ค.)
์ค์
๋ค์ ์์น์ ์ถ๊ฐ
messages.properties
hello=์๋
hello.name=์๋
{0}
{0}์ ํ๋ผ๋ฏธํฐ์ด๋ค. (์ฌ๋ฌ๊ฐ๋ฉด, 0,1,2, ...)
๊ตญ์ ํ ๊ธฐ๋ฅ๋ ์ ์ฉํด๋ณด์
messages_en.properties
hello=hello
hello.name=hello {0}
๋ง์ฝ ์์ด๊ถ์์ ๋ค์ด์จ๋ค๋ฉด en์ ์ฌ์ฉํ๊ณ , ๋๋จธ์ง(en์ด ์๋ ๊ณณ)์์ ๋ค์ด์ ๋ฉ์์ง ์์ค๋ฅผ ์ฐพ์ ์ ์๋ค๋ฉด ๊ธฐ๋ณธ์ ์ธ messages.properties๋ฅผ ์ฌ์ฉํ๋ค.
์ฌ์ฉ (ํ ์คํธ์ฝ๋)
@Autowired
MessageSource messageSource;
@Test
public void helloMssage() throws Exception {
String message = messageSource.getMessage("hello", null, null);
//๋ฉ์์ง ์์ค ํ์ผ๋ค ์ค์์, hello์ ํด๋นํ๋ ๊ฒ์ ์ฐพ์, ๋งค๊ฐ๋ณ์๋ ์๊ณ , ๊ตญ๊ฐ๋ null => ๋ฐ๋ผ์ ๊ธฐ๋ณธ๊ฐ์ธ messages.properties๊ฐ ์ ์ฉ
assertThat(message).isEqualTo("์๋
");
String messageEn = messageSource.getMessage("hello", null, Locale.ENGLISH);
//๋ฉ์์ง ์์ค ํ์ผ๋ค ์ค์์, hello์ ํด๋นํ๋ ๊ฒ์ ์ฐพ์, ๋งค๊ฐ๋ณ์๋ ์๊ณ , ๊ตญ๊ฐ๋ ์์ด๊ถ => ๋ฐ๋ผ์ messages_en.properties๊ฐ ์ ์ฉ
assertThat(messageEn).isEqualTo("hello");
messageEn = messageSource.getMessage("hello", new Object[]{"์ ๋ํ","๋ฐ๋ณด"}, Locale.ENGLISH);
//๋ฉ์์ง ์์ค ํ์ผ๋ค ์ค์์, hello์ ํด๋นํ๋ ๊ฒ์ ์ฐพ์, ๋งค๊ฐ๋ณ์๋ ์ ๋ํ, ๋ฐ๋ณด, ๊ตญ๊ฐ๋ ์์ด๊ถ
// => ๋ฐ๋ผ์ messages_en.properties๊ฐ ์ ์ฉ, ๊ทธ๋ฌ๋ hello๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ์ ์ ๋ํ๊ณผ ๋ฐ๋ณด๋ ๋ฌด์
assertThat(messageEn).isEqualTo("hello");
messageEn = messageSource.getMessage("hello.name", new Object[]{"์ ๋ํ","๋ฐ๋ณด"}, Locale.ENGLISH);
assertThat(messageEn).isEqualTo("hello ์ ๋ํ");
//๋ฉ์์ง ์์ค ํ์ผ๋ค ์ค์์, hello.name์ ํด๋นํ๋ ๊ฒ์ ์ฐพ์, ๋งค๊ฐ๋ณ์๋ ์ ๋ํ, ๋ฐ๋ณด, ๊ตญ๊ฐ๋ ์์ด๊ถ
// => ๋ฐ๋ผ์ messages_en.properties๊ฐ ์ ์ฉ, ๊ทธ๋ฌ๋ hello.name์ ๋งค๊ฐ๋ณ์๋ฅผ ๋จ ํ๋๋ง ์ฌ์ฉํ๋ฏ๋ก ๋ฐ๋ณด๋ ๋ฌด์
assertThrows(NoSuchMessageException.class, ()-> messageSource.getMessage("no_match",null,Locale.KOREA));
//๋ฉ์์ง ์์ค ํ์ผ๋ค ์ค์์, no_match์ ํด๋นํ๋ ๊ฒ์ ์ฐพ์, ๊ทธ๋ฌ๋ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก NoSuchMessageException ๋ฐ์
String noSuchMessage = messageSource.getMessage("no_match", null, "๊ธฐ๋ณธ ๋ฉ์ธ์ง", Locale.KOREA);
//๊ธฐ๋ณธ ๋ฉ์์ง๋ฅผ ์ค ์ ์์
assertThat(noSuchMessage).isEqualTo("๊ธฐ๋ณธ ๋ฉ์ธ์ง");
}
์ฌ์ฉ (์์ธ์ฒ๋ฆฌ - ControllerAdvice)
@RestControllerAdvice
public class ExceptionAdvice {
@Autowired
MessageSource messageSource;
@ExceptionHandler(Exception.class)
public ResponseEntity handleBaseEx(Exception exception, Locale locale){
String message = messageSource.getMessage(exception.getMessage(), null, locale);
... ์๋ต
}
}
์ด๋ฐ ์์ผ๋ก Rest API์์ ์์ธ ๋ฉ์์ง์ ๊ตญ์ ํ ์ฒ๋ฆฌ๋ ํ ์ ์๋ค.
LocaleResolver
์คํ๋ง์ Locale ์ ํ ๋ฐฉ์์ ๋ณ๊ฒฝํ ์ ์๋๋ก LocaleResolver๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋๋ฐ, ์คํ๋ง ๋ถํธ๋ ๊ธฐ๋ณธ ์ค์ ์ผ๋ก Accept-Language๋ฅผ ํ์ฉํ์ฌ Locale์ ๊ฒฐ์ ํ๋ AcceptHeaderLocalResolver๋ฅผ ์ฌ์ฉํ๋ค.
๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ์์๋ก Locale ์ ํ ๋ฐฉ์์ ๋ฐ๊พธ๊ณ ์ถ๋ค๋ฉด, ํด๋น LocaleResolver๋ฅผ ์์๋ฐ์ ๊ตฌํํ ๊ตฌํ์ฒด๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํด์ฃผ๋ฉด ๋๋ค.