국제화(Internalization)는 다양한 언어와 지역에서 애플리케이션이 작동할 수 있도록 디자인하는 프로세스이다. 이것은 text label을 다른 언어로 번역하는 것 뿐만 아니라 날짜나 시간과 같은 정보를 특정지역의 형식에 맞게 표시하는 것을 뜻한다.
text label과 메시지를 국제화 하는 첫번째 과정은 모든 정보를 리소스 번들로 옮기는 것이다. 이 때 각각의 인용된 스트링을 사용자가 볼 수 있게 하기 위해서는, 우선 리소스 번들에 엔트리를 만들고, text label과 메시지가 사용자가 위치한 지역에 따라 다이내믹하게 변하도록 코드를 바꿔줘야 한다. 이것을 제대로 했을 때, 미국에 있는 사용자는 Help를, 스페인에 있는 사용자는 Ayuda를 도움 메뉴를 나타내는 라벨로 이해할 것이다.
이러한 기법은 전체가 하나의 메시지로 되어 있어서 text에서 text로의 번역이 가능한 경우에는 완벽하게 들어맞지만, 여러 개의 메시지로 이루어진 하나의 긴 메시지의 경우에는 그렇지 않다. 다음의 예를 보자.
Hello, John. Good luck.
사용자는 여기에서 단순하게 연결된 스트링(string concatenation)을 떠올리며, 다음과 같이 여러 개의 스트링을 덧붙이는 방법으로 합성된 메시지를 만들려고 할 것이다.
System.out.println(
"Hello, " +
name +
". Good luck.")
혹은, Hello 와 Good luck 스트링을 리소스 번들로 옮겨 가면서 메시지를 합성시키려는 생각을 할 지도 모른다. 사실 이 방법은 잘 돌아갈 수도 있다. 하지만 인사말의 형태가 다음과 같이 나타나는 현상이 일어난다.
Hello and good luck, John.
그렇다면 이번엔 리소스 번들 스트링을 이름 앞, 뒤의 접두사와 접미사 부분으로 구별해서 쪼개는 방법을 생각해 보자. 하지만 이 때에는 번역가가 어떤 것들이 같이 쓰이는지 그 용법을 모두 알고 있어야만 하기 때문에 일을 더욱 복잡하게 만들 뿐이다. 따라서 이보다 나은 접근방법은 가운데에 이름 변수를 넣을 수 있는 텍스트 스트링(text string)을 만들어 주는 것이다.
영어의 경우에는 다음과 같다.
Hello, {0}. Good luck.
이렇게해서 생성된 스트링을 본다면, 스페인어 번역가는 다음과 같이 hello 와 good luck 을 함께 넣어버리는 것이 더 낫다는 것을 깨닫게 될 것이다.
Hola y buena suerte, {0}.
이 메시지가 실제적으로 디스플레이 될 때에는 java.text 패키지의 MessageFormat 클래스가 변수들을 대체하기 위해 사용된다. 이 때 MessageFormat은 한 세트의 객체들을 가져와서 그것들을 포맷하고, 포맷된 스트링을 "Hello, {0}. Good luck." 과 같은 패턴에 삽입한다.
MessageFormat을 사용하기 위해서는 우선 formatter를 생성해야 한다.
String pattern = ...; // from bundle Locale aLocale = ...; // the Locale MessageFormat formatter = new MessageFormat(pattern); formatter.setLocale(aLocale);
각각의 패턴을 만들기 위해서는 그에 대응하는 각각의 다른 MessageFormat 객체를 생성할 수도 있지만, 새로운 패턴 템플릿에 applyPattern 메소드를 호출함으로써 또 다른 패턴을 가진 MessageFormat 객체를 재사용 할 수도 있다. 이것은 지역정보(locales)를 바꾼 후에 해야 하는 작업임을 기억하자.
formatter.setLocale(aNewLocale); formatter.applyPattern(aPatternForNewLocale);
포맷터를 만든 후에는 출력 메시지를 생성해야 한다. 이를 위해서는 인수(argument)들의 배열(array)을 넘겨 주어야 하는데, 배열안의 인덱스값에 따라서 패턴안의 각 {#}을 이 인수들의 배열이 교체해주게 된다. "Hello, {0}. Good luck." 이라는 패턴을 위해서는 하나의 요소를 갖는 배열이 필요하고, 이 배열안의 요소는 스트링의 위치0에 삽입될 텍스트를 포함한다는 것이다. 앞서 설명한 패턴에 "John" 이라는 스트링값을 삽입한 한개의 요소를 갖는 배열의 예가 있다.
Object messageArgs[] = {"John"};
출력값을 생성하기 위해선, message arguments을 지정하여 MessageFormat의 포맷 메소드를 호출한다.
System.out.println(formatter.format(messageArgs));
아래의 HelloGoodLuck 프로그램은 MessageFormat이 어떻게 사용되는지 보여주고 있으며, 여기에서는 프로그램을 간단하게 유지하기 위해 리소스 번들을 사용하지 않는다.
import java.text.*;
import java.util.*;
public class HelloGoodLuck {
public static void main(String args[]) {
String pattern = "Hello, {0}. Good luck.";
Locale aLocale = Locale.US;
MessageFormat formatter = new MessageFormat(
pattern, aLocale);
Object messageArgs[] = {"John"};
System.out.println(
formatter.format(messageArgs));
// Pass in command line args
if (args.length != 0) {
System.out.println(formatter.format(args));
}
}
}
커맨드 라인에 이름값을 주면 HelloGoodLuck프로그램은 두번째 메시지를 산출한다.
예를 들어, 다음과 같은 명령을 주고 프로그램을 실행했을 때,
java HelloGoodLuck Spot
이와 같은 출력값을 보게 될 것이다.
Hello, John. Good luck. Hello, Spot. Good luck.
MessageFormat을 사용하면 텍스트를 대입하는 기능뿐만 아니라, NumberFormat 이나 DateFormat 클라스를 사용하지 않고서도 숫자나 날짜를 포맷할 수가 있다. javadoc은 MessageFormat 클라스에서 가능한 모든 지원에 대해 설명하고 있으니 이를 참고하길 바란다.
{#}의 argument index 뒷부분에는 포맷의 타입과 스타일을 컴마로 구분해서 지정할 수 있다. 예를 들어 날짜의 경우, short, medium, long, full 등의 타입을 지정하여 DateFormat 상수(constants)에 매핑할 수 있다. 만약 이때 인수의 타입이 Date이고, MessageFormat이 "{1,date,long}"을 인수로 갖는다면, 출력값으로 지역에 맞는 포맷에 long 타입으로 디스플레이 된 날짜를 보게 될 것이다. 또한 똑같은 short, medium, long, full 옵션을 이용해서 날짜를 "시간"과 함께 디스플레이할 수도 있다. 여기에서 숫자값에는 정수(integer), 통화(currency), 퍼센트(percent) 스타일도 가능하다. 만약 이렇게 미리 짜여진 스타일이 싫다면, 또 SimpleDateFormat과 DecimalFormat의 패턴 스트링을 이미 알고 있다면, 정보를 직접 명시해서 사용해도 된다.
시간, 날짜, 숫자를 사용하는 MessageFormat 패턴의 예를 보자.
At the tone, the time is now {0, time, short}
on {0, date, long}.
You now owe us {1, number, currency}.
입력 인수로 Date와 Number를 주었다면, 미국과 독일 지역에 맞는 출력값을 보게 될 것이다.
다음은 위의 출력값을 생성한 프로그램이다. 단순한 프로그램을 위해서는 리소스 번들을 사용하지 말고, 대신에 패턴변수와 germanPattern 변수의 스트링을 리소스 번들에 위치시켜야 한다.
import java.text.*;
import java.util.*;
import java.io.*;
import java.awt.*;
import javax.swing.*;
public class ExtendedFormat {
public static void main(String args[]) {
String pattern =
"At the tone, the time is now {0, time, short}" +
" on {0, date, long}." +
" You now owe us {1, number, currency}.";
String germanPattern =
"Beim Zeitton ist es {0, time, short} Uhr" +
" am {0, date, long}." +
" Sie schulden uns jetzt {1, number, currency}.";
StringWriter sw = new StringWriter(100);
PrintWriter out = new PrintWriter(sw, true);
MessageFormat formatter =
new MessageFormat(pattern, Locale.US);
Object messageArgs[] =
{new Date(), new Double(9000.12)};
out.println(formatter.format(messageArgs));
formatter.setLocale(Locale.GERMAN);
// Need to reset pattern after changing locales
formatter.applyPattern(germanPattern);
out.println(formatter.format(messageArgs));
out.close();
// Put output in window
JFrame frame = new JFrame("Extended Format");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
JTextArea ta = new JTextArea(sw.toString());
JScrollPane pane = new JScrollPane(ta);
frame.getContentPane().add(
pane, BorderLayout.CENTER);
frame.setSize(500, 100);
frame.show();
}
}
MessageFormat 을 사용하는 것 말고도 애플리케이션을 국제화하는 방법은 매우 많다. 스트링 패턴의 출처인 리소스 번들의 사용에 관한 자세한 사항은 "Resource Bundles" 1998/5/21 Tech Tip을, 날짜와 시간 스트링 포맷에 관한 자세한 정보는 "Internationalizing Dates, Times, Months, and Days of the Week" 2003/6/24 Tech Tip을 참고하길 바란다.
"Java SE" 카테고리의 다른 글
- 리스너 리스트를 위한 WEAKHASHMAP 사용하기 (댓글 1개 / 트랙백 0개) 2006/03/08
- J2SE 5.0의 Java 2D API 기능 강화 (댓글 2개 / 트랙백 0개) 2006/05/12
- 3D 화면(scene)에 빛 효과 주기 (댓글 1개 / 트랙백 0개) 2004/07/30
- 다이얼로그 Modality (댓글 1개 / 트랙백 0개) 2006/06/09
- 쿠키 처리 (댓글 22개 / 트랙백 3개) 2007/07/23
- 사용자 데이터그램 프로토콜의 프로그래밍 (댓글 1개 / 트랙백 0개) 2004/06/30
- 락(LOCKS) (댓글 1개 / 트랙백 0개) 2005/09/22
- Java Web Start 퍼시스턴스 (댓글 3개 / 트랙백 0개) 2006/12/24
- AFFINETRANSFORM 이해하기 (댓글 3개 / 트랙백 0개) 2003/09/09
- 사용자 인터페이스에서 Action 사용하기 (댓글 5개 / 트랙백 2개) 2007/02/22
TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/260
-
Java SE / 초급 예외처리하기
Tracked from 함께 가꾸는 세상 삭제자바에서 예외처리하기에 대하니 기본 강좌. 자바 공부할 때 중요하고 기본적이면서도, 제대로 이해하지 못하는 경우가 많은 예외처리.. 한 번 제대로 배워보자. http://www.sdnkorea.com/blog/248
2007/09/15 14:38
댓글을 달아 주세요
좋은 정보 감사 드립니다! ^^
2007/09/05 20:03sdnkorea.com엔 유용한 정보가 많은것 같습니다.^^
2007/09/08 08:29처음보는게 많네요~
국제화.. 해볼일이 없어서 쓸일도 없었는데..
2007/09/13 11:21이런거였군요..^^ 좋네요~
덕분에 한단계 더 성장한 기분이네요.
2007/09/19 02:12좋은 정보 감사해요~
2007/09/19 06:23좋은 정보 감사드려요~
2007/09/19 22:55좋은 정보 감사드려요.
2007/09/19 23:13많이 배우고 가요 ^^