2015년 6월 27일 토요일

국제화된 소프트웨어에서 날짜와 시간을 다루는 방법 (18)

개발자들이 소프트웨어를 개발하면서 가끔 하는 실수 중 하나가 현지 시간을 저장했다가 나중에 소프트웨어가 확장되면서 꼬이는 것이다. 보통의 소프트웨어라면 시간에 그렇게 민감하지 않다. 하지만 일정관리, 항공권 예약, 배송 시스템 등 시간에 민감한 소프트웨어들이 있다. 이 외에도 시간을 신경 써서 다뤄야 하는 소프트웨어가 많다. 이런 소프트웨어에서 시간의 기록과 처리를 현지 시간을 기준으로 처리를 하다가는 문제가 발생하고 꼬이게 된다. 



여기서 현지 시간이란 날짜와 시각을 모두 의미한다. 또 현지 시각은 그레고리력을 기준으로 하는 날짜 일 수도 있고 해당 나라에서 사용하는 독특한 달력을 기준으로 한 날짜일 수도 있다. 개인 혼자서 쓰는 시스템, 예를 들어 일기장과 같은 소프트웨어라면 문제가 안되지만 전세계 여러 사용자가 공유하는 시스템이라면 시간의 표시가 지역마다 다르게 표시되어야 한다. 또한 혼자 사용하더라도 일정 관리 소프트웨어 같은 경우에는 지역을 옮겨 다닐 때마다 현지 시간에 맞게 보정해서 보여줘야 한다.

그래서 시스템에 시간을 저장할 때는 절대 시간을 기록해야 한다. 소프트웨어에서 절대 시간이란 유닉스 시간을 말한다. POSIX 시간이라고도 부른다. 유닉스 시간은 영국 그리니치 천문대에서 그레고리력으로1970년 1월 1일 0시 0분 0초에 0으로 시작된 시간 표시로 1초에 1씩 증가한다. 예를 들어 한국에서 2015년6월5일 오전2시16분37초의 유닉스 시간은 1433524597이다. 거의 모든 OS와 Database에서는 유닉스 시간을 기준으로 시간을 처리한다. 그리고 화면에 출력할 때 타임존을 고려하여 변환하여 출력한다. 

따라서 시간을 기록할 때는 유닉스 시간을 얻어와서 DB나 파일에 저장을 하고 입출력 시 사용자의 입맛에 맞게 변환을 해야 한다. 출력 시에는 예를 들어 아래와 같은 변환 과정을 거쳐야 하고, 입력 시는 반대 과정을 거친다.


(유닉스 시간 10억초 달성 기념)

1. 유닉스 시간 : 1433524597
2. 협정 세계시 : 2015-06-05 17:16:37 UTC
3. 달력 변환 : 2015-06-05 17:16:37 UTC
4. 한국의 타임존 : 2015-06-06 02:16:37+09:00(or PDT)
5. 한국의 시간포맷 : 2015년 6월 6일,오전 2시 16분 37초

1~4번까지는 소프트웨어 내부에서 일어나는 변환 과정이고 5번이 사용자에게 보여지게 된다. 또한 형식은 언어(로케일)별로 다르다.

달력 변환에서 그레고리력일 경우에는 변환할 필요가 없지만 사용자가 그레고리력이 아닌 다른 달력을 사용하는 경우에는 변환이 필요하다. 예를 들어 일본 일왕의 연호나 불기, 음력을 사용한다면 변환이 필요하다.

개발 환경 즉, 개발 프레임워크나 라이브러리에서 제공하는 시간 함수들은 여러가지가 있고 위 변환 과정을 거의 모두 지원하는 것도 있고 일부만 지원해서 개발자가 추가로 개발을 해야 하는 경우도 있다. 대부분은 유닉스 시간과 타임존 변환은 제공하지만 달력 변환을 지원하는 경우는 거의 없고 로케일별 시간 포맷 제공도 프레임워크마다 제각각이다. 개발자가 상당한 세심한 신경을 써야 하는 이유다.


(타임존 지도)

그 외에 일정관리나 항공권예약 시스템에서는 시간과 관련해서 좀더 많은 정보를 보관해야 한다. 매 시간마다 위치나 타임존을 기록해서 하나의 시간에 대해서도 현지 시간과 현재 사용자가 있는 위치의 시간을 동시에 보여주기도 한다. 국제화가 잘된 소프트웨어에서는 시간 처리에 여러 가지 신경을 써야 한다.

그럼 국가별, 로케일별로 시간 표시 형식은 어떨까? 우선 로케일별 국가 이름을 보자

ar_SA : 사우디아라비아
de_DE : 독일
en_US : 미국
es_ES : 스페인
fr_FR : 프랑스
id_ID : 인도네시아
it_IT : 이탈리아
ja_JP : 일본
ko_KR : 대한민국
pl_PL : 폴란드
pt_PT : 포르투갈
ru_RU : 러시아
vi_VN : 베트남
zh_CN : 중국
zh_TW : 타이완
de_LI : 리히텐슈타인
th_TH : 태국

로케일(국가)별 시간 형식의 예는 다음과 같다. 

ar_SA : " ٣:٠٢:٢٧ م"
de_DE : "15:02:27"
en_US : "3:02:27 PM"
es_ES : "15:02:27"
fr_FR : "15:02:27"
id_ID : "15.02.27"
it_IT : "15:02:27"
ja_JP : "15時02分27秒"
ko_KR : "오후 3시 2분 27초"
pl_PL : "15:02:27"
pt_PT : "15:02:27"
ru_RU : "15:02:27"
vi_VN : "15:02:27"
zh_CN : "下午3时02分27秒"
zh_TW : "下午3時02分27秒"
de_LI : "15:02:27 "
th_TH : "15 นาฬิกา 2 นาที 27 วินาที "

위 시간의 포맷은 특정 Framework를 사용한 한 예다. 

물론 모든 소프트웨어가 위에서 언급한 타임존, 특수한 달력, 지역에 맞는 형식을 모두 지원하는 것은 아니다. 또한 우리가 만드는 소프트웨어도 모두 지원해야 하는 것은 아니다. 소프트웨어 성격과 판매 지역, 전력에 따라서 지원해야 하는 범위를 개발 초기에 결정해야 한다. 그래야 소프트웨어 국제화가 성공적으로 진행될 수 있다.

많은 소프트웨어에서 단수/복수 번역이 엉터리인 이유 (17)

앞으로 번역에 대해서 다룰 여러 주제 중에서 오늘은 단수/복수에 대해서 알아보자. 

국제화/지역화가 잘 된 소프트웨어라고 하더라도 단수/복수를 제대로 처리하고 있는 소프트웨어는 찾아보기 쉽지 않다. 우리는 단수/복수에 대한 구분을 하지 않는 언어를 사용하고 있다. 그래서 단수/복수 처리에 대해서 민감하지 않다. 하지만 단수/복수를 구분하는 언어권에서는 이를 제대로 처리하지 않으면 어색한 표현이 된다. 물론 의미는 알아보겠지만 그만큼 소프트웨어의 품질은 떨어지게 된다.




많은 소프트웨어에서 단수/복수 처리가 어렵기 때문에 꼼수를 부리곤 한다. 예를 들어 “%d file has been deleted”라는 문장을 사용해서 %d는 파일의 개수, 즉 숫자로 교체가 가능하다고 보자. 파일이 한 개라면 “1 file has been deleted”이 되지만 파일이 5개라면 “5 file has been deleted”가 되어서 어색한 문장이 된다.

그래서 “5 file(s) has been deleted”라고 하곤 하는데 has도 어색하다. 결국 “%d file(s) has(have) been deleted”라는 포맷을 이용하여 “5 file(s) has(have) been deleted”라고 할 수는 있지만 몹시 보기 지저분한 문장이 아닐 수 없다. 그래서 처음부터 “The number of deleted files: 5” 이와 같이 단수/복수와 무관한 문장들을 만들어 내지만 부자연스러운 것은 여전하다.

그리고 file(s)와 같은 꼼수를 쓰는 것은 영어나 몇몇 언어에서만 통한다. 우리나라 대부분의 개발자들은 한국어와 영어에 익숙하기 때문에 전세계 대부분의 언어가 그 틀에 크게 벗어나지 않으려니 추측하지만 우리가 상상할 수 없는 언어는 매우 많다.




예를 들어 폴란드어를 보자. 폴란드어에서 file은 plik이다. 이것은 단수 표현이다. 즉 file이 하나면 plik다. 그리고 2개면 pliki다. 3,4개도 pliki다. 하지만 5개가 되면 pliko’w로 바뀐다. 게다가 21개까지만 pliko’w다. 말로 설명하면 복잡하니 아래를 보라.

1 plik
2,3,4 pliki
5-21 pliko'w
22-24 pliki
25-31 pliko'w
32-34 pliki
35-41 pliko'w

복수의 형태가 두 가지인데 애매한 구간에서 바뀌며 끝에 ‘s’를 붙이는 형태도 아니다. 그래서 영어에서나 사용하던 끝에 (s)를 붙이는 형태로는 번역이 안된다. 

우리와 같이 단수/복수 구분을 하지 않는 언어는 일본어, 베트남어가 있다. 그리고 영어처럼 2개부터 복수로 처리를 하는 언어는 독일어, 스페인어, 이탈리아어, 그리스어, 터키어 등 가장 많은 언어가 여기에 속한다. 하지만 라트비아, 루마니아, 리투아니아, 러시아, 우크라이나, 크로아티아, 체코, 슬로베니아 등은 제각각 다른 단수/복수 체계를 가지고 있다. 

이런 상황에서 file(s)와 같이 쓰던가 단수/복수 처리를 별 것 아니라고 모두 단수로 처리해서 소프트웨어를 사용하라고 하는 것은 소프트웨어의 품질을 떨어뜨리는 결과가 된다. 현재도 여전히 많은 소프트웨어가 단수/복수 처리를 제대로 하고 있지는 않다.

그럼 소프트웨어에서 단수/복수 처리를 어떻게 할 수 있을까? 구체적인 방법은 추후 소개를 하도록 하겠다.



(을를이가 문제를 피해간 사례)

이와 유사한 문제로는 “을를이가은는” 문제가 있다. 한국어에만 있는 이슈인데 소프트웨어에서 “%s을 삭제했습니다.”라는 형식을 이용해서 %s를 “파일” 또는 “이미지”로 교체를 해서 출력한다고 보자. 이때 “이미지”로 교체를 하면 “이미지을”이라는 어색하는 문장이 된다. 그래서 “%s을(를) 삭제했습니다.”이라고 꼼수를 쓰던가 “파일을 삭제했습니다.”와 “이미지를 삭제했습니다.” 두 문장을 각각 번역하기도 한다. 하지만 %s에 들어가야 할 단어의 개수가 많고 문장이 조금만 더 복잡하면 번역해야 할 문장이 기하급수로 늘어서 좋은 방법은 아니다. 

단수/복수 문제는 전세계적인 문제라서 이를 연구하는 사람이 많지만 “을를이가은는”문제는 우리가 스스로 해결해야 한다. 

단수/복수 문제는 사소해 보이지만 무시할 수 없는 이슈이고 이러한 수준의 이슈들은 소프트웨어 번역에서 수 많이 존재한다. 급한 개발자나 경영자들은 언제 이런 이슈까지 신경을 쓰면서 소프트웨어를 개발하고 국제화를 하겠냐고 하소연을 하거나 스스로 해결을 해보고자 연구하고 라이브러리를 만들고 있을 수도 있다. 



하지만 소프트웨어 국제화는 이미 이전의 개발자들이 많이 연구를 해놓았고 해결책을 제시해 놓았기 때문에 대부분의 문제는 이미 제시된 해결책을 잘 찾아서 사용하기만 하면 된다. 스스로 해결해야 하는 문제도 있지만 이미 나와 있는 솔루션을 모르고 또 만드는 경우도 많다.물론 그렇게 재탄생한 자체 솔루션의 99%는 함정에 빠져서 문제를 완벽하게 해결하지 못한다. 이런 현상은 집을 만들기 위해서 망치가 없다고 망치를 직접 만드는 것과 비견된다. 

그래서 소프트웨어 국제화에는 방대한 지식이 필요한 것이다. 무엇이 필요하고 누가 이미 만들어 놓은 것들에는 어떤 것들이 있는지 알려면단편적인 지식보다는 소프트웨어 국제화 전반에 걸쳐 광범위한 지식이 필요하다. 

본 시리즈의 포스트를 통해서 조금씩 알아나가도록 하자.

소프트웨어 번역이 생각보다 훨씬 어려운 이유 (16)

이제부터 소프트웨어 국제화에서 가장 중요한 번역과 관련된 얘기를 시작하려고 한다. 번역은 다뤄야 할 주제가 광범위하므로 여러 회차를 거쳐서 다루게 될 것이다. 필자는 수십 개의 회사의 소프트웨어 국제화 방식을 조사했으며 대부분의 회사가 수많은 번역 함정에 빠져서 어려움을 겪고 있는 것을 보았다. “변역 함정”이란 소프트웨어를 번역하면서 비효율적인 방법에 쉽게 빠져서 허우적거리는 것을 말한다. 번창한 회사일수록 어려움은 더 커졌다. 그래서 어떻게 하면 번역 함정에 빠지지 않고 효율적인 번역을 통해서 소프트웨어 국제화를 성공할 수 있는지 공유를 할 것이다.


가상의 A사는 전세계 수십 개의 국가에서 사용하는 서비스를 개발하고 있다. 해당 서비스를 개발하는 소프트웨어 엔지니어는 수십 명에 이른다. 해당 서비스는 10개 언어로 번역이 되어서 서비스가 되고 있다.

그러다 보니 개발자는 소스코드에 번역이 필요한 메시지 하나를 추가하려고 해도 매우 복잡한 절차를 밟아야 한다. 소스코드에 “Hello”라는 메시지를 넣어야 한다고 가정해보자. A사의 개발자는 다음과 같은 프로세스를 밟아야 한다.

1. “Hello”에 대응하는 심볼을 정한다. MSG_HELLO로 정했다.

2. 소스코드에는 TranslateMsg("MSG_HELLO")라고 번역 함수를 이용해서메시지를 입력한다. 이 단계에서 소프트웨어는 MSG_HELLO라고 출력된다.

3. 개발자들이 공유하는 엑셀 파일에 “MSG_HELLO” 항목을 추가하고 영어 칸에 “Hello”를 입력한다. 이때 엑셀 파일은 여러 개발자가 공유를 해야 하기 때문에 소스코드 관리시스템이 아니고 파일서버에 보관하고 있다.

4. 해당 엑셀 파일에는 10개 언어별 컬럼이 있는데 각 언어별로 이번 업데이트에 추가된 메시지를 10개의 엑셀파일로 추출하여 언어별 번역가에게 번역을 의뢰한다.

5. 번역이 완료된 후에 엑셀파일은 각 언어별 메시지 파일로 저장한다. (예, Korea.ini, Japan.ini)

6. 이제 소프트웨어에서는 “MSG_HELLO” 대신 “Hello”가 출력된다.


가상의 A사의 예를 들었지만 현실과 전혀 동떨어진 얘기는 아니다. 위 프로세스를 보고 별일 아니라고 생각할 수도 있고 복잡하고 불편하다고 생각할 수도 있다. 아직 국제화된 소프트웨어를 개발해보지 못한 개발자나 한두 개 언어를 추가로 개발해본 개발자는 소프트웨어 번역의 복잡함을 과소 평가할 수도 있다.

하지만 소프트웨어는 지원해야 하는 언어가 많을수록 소프트웨어 규모가 클수록 개발팀의 규모가 클수록 업데이트 주기가 잦을수록 번역의복잡도는 기하급수로 증가를 한다. 

자연스러워 보이는 위 예도 이미 수많은 함정에 빠져서 매우 비효율적인 프로세스를 밟고 있는 상태다. 물론 소프트웨어가 잘 안 팔려서 사라져가고 있다면 번역의 복잡성 함정에 빠져서 문제가 되고 있다는 사실 조차 모르고 지나간다. 하지만 2,3개 지원하던 언어를 10개 이상으로 늘려서 지원하게 되고 소프트웨어가 계속 업그레이드되어서 규모가 몇배 커지고 개발자도 많이 투입이 된다면 그 때서 번역 프로세스로 인한 비효율이 눈에 띄게 커졌다가는 것을 발견하게 된다.

그때는 이미 소프트웨어 번역 아키텍처를 바꾸기 어려운 상태이기 때문에 비효율을 개선하기는 매우 어려워진다. 번역은 실제 메시지가 현지 문화에 얼마나 잘 맞게 번역이 되었는지도 중요하지만 어떤 메시징 아키텍처를 사용하는지도 중요하고 번역 프로세스도 매우 중요하다.

흔히 RC 파일을 사용하기도 하고 자체적으로 제작한 메시징 함수를 사용하기 위해서 INI파일이나 별도의 메시지 파일을 포맷을 만들어서 사용하기도 한다. 이 과정에서 중간 파일로 엑셀파일을 사용하기도 하고Database를 사용하는 회사도 있다. 개발자가 번역이 필요한 메시지 하나를 소스코드에 추가하기 위해서 복잡한 절차를 밟아야 하는 경우가 많다.

이런 복잡한 절차의 불편함을 당연하게 생각하고 개발하는 개발자도 있는가 하면 이를 개선해보고자 여러 자동화 툴을 만들면서 노력을 했지만 쉽게 개선되지 않음을 경험하기도 한다.

앞으로 소프트웨어 번역의 원칙과 원리를 중심으로 가장 효율적으로 번역을 하는 방법을 공유하도록 하겠다.

독특한 달력을 사용하는 고집 센 나라들 (15)

미국에서 미터법을 잘 쓰지 않듯이 국제 표준이 있는데 자국만의 표준을 고집하는 나라들이 있다. 우리가 모든 나라의 문화를 다 이해하지 못하는 상황에서 이를 비난 해서는 안된다. 다만 소프트웨어를 개발하는데 엄청 번거로울 뿐이다. 날짜에서도 전세계 대부분의 나라가 그레고리력을 사용하는데 그레고리력을 사용하지 않는 몇몇 나라가 있다. 물론 그레고리력과 혼용을 하기도 한다.

게다가 달력은 로케일 표준 카테고리에 해당하지 않기 때문에 대부분의 개발툴이나 라이브러리에서 별도로 제공하지 않는다. 개발자가 직접 제공을 해야 하는 경우가 많다.




사실 한국도 19세기까지는 음력을 사용하다가 독자 연호를 거쳐 현재는 그레고리력을 쓴다. 우리나라는 국제 표준을 상당히 잘 따르는 나라 중에 하나다. 오랫동안 써왔던 면적 단위인 “평”을 못 쓰도록 법으로 금지했는데 이렇게 할 수 있는 나라는 그렇게 많지 않을 것이다. 그래도 그런 강제 표준 적용이 소프트웨어 개발에는 더 유리하다.
이렇게 전세계가 완벽하게 그레고리력으로 통일되지 못한 상황에서 소프트웨어가 그레고리력만 제공을 하면 해당 국가에서는 받아들여지기 힘들 수도 있다. 그래서 그레고리력 외에 크게 “불기”와 일본의 “연호”를 제공해야 한다. 그 외에는 여러 가지 달력이 추가로 더 있으니 소프트웨어의 성격에 따라서 추가 지원을 고려해야 한다.




먼저 “불기”를 알아보자. “불기”란 석가모니가 입적(불멸)한 해인 기원전544년을 기준으로 삼는 달력이다. “서기”는 예수의 탄생을 기준으로 삼는데 불교에서는 정반대의 기준을 사용하는 것으로 보아서 문화에 따른 생각의 차이를 엿볼 수 있다.

표준 “불기”로는 올해가 2559년이지만 태국에서는 이보다 1년 늦은 2558년이다. “불기”도 나라별로 약간 다른 것도 소프트웨어에서는 여간 귀찮은 일이 아니다. 또한 태국에서는 그레고리력을 쓰는 사람들도 있기 때문에 그레고리력을 선택할 수도 있도록 해야 한다. 즉, 로케일로 달력을 결정할 수 없고 별도의 설정이 필요하다.

다음은 일본이다. 일본은 일왕에 따른 연호를 사용한다. 올해는 平成27年(헤이세이)이다. 일본 역시 그레고리력도 쓰기 때문에 둘 다 지원을 해야 한다. 일본의 연호를 고려하지 않고 소프트웨어를 개발하게 되면 올해가 2015년이 아니고 0027년으로 처리가 될 수도 있다. 일본은 연도별로 연호가 다르기 때문에 대단히 귀찮은 변경작업을 해줘야 한다. 하지만 연호를 잘 제공하면 그만큼 일본 시장에서 소프트웨어의 품질이 올라갈 것이다.

그 외에 몇 개의 달력을 더 알아보자. 필자도 위의 달력 외에도 아래 소개하는 몇몇 달력 때문에 고생한 적이 있다.

이슬람력은 많은 이슬람 국가에서 사용하고 대부분의 나라에서는 그레고리력과 병기를 한다. 위에서 언급한 불기와 일본의 연호는 연도만 다르고 월과 일은 그레고리력과 같다. 하지만 이슬람력은 태음력을 사용하기 때문에 날짜가 완전히 다르다. 라마단도 이슬람력을 기준으로 한다.

이란과 아프가니스탄에서 사용하는 이란력(페르시아력)도 있다. 이는 태양력이다.

그 외에도 히브리력, 인도 국민력, 에티오피아력, 대한민국 단기, 음력, 북한의 주체연호가 있다. 대부분은 그레고리력과 병기를 한다.

어떤 달력을 지원하던지 날짜의 변환 작업과 날짜 선택기를 제공해야 한다. 그레고리력 날짜 선택기를 쓸 수 없는 달력들이 있다.

소프트웨어를 개발할 때 달력을 어디까지 제공할지는 소프트웨어의 성격과 판매하려는 지역과 전략에 따라서 매우 달라진다. 우리가 각 나라들의 문화를 다 알지 못하는 상황에서 무조건 그레고리력을 써야 한다고 주장하는 것은 소프트웨어 판매에 걸림돌이 될 수도 있고 그렇다고 모든 달력을 제공하는 것은 배보다 배꼽이 더 클 수도 있다. 전략에 따라서 적절히 판단을 해야 한다.

날짜 표기 국제 표준은 무엇일까? (14)

지난 12회에서 국가별, 로케일별로 날짜 표기 형식이 매우 다르다는 것을 보았다. 하지만 이런 방식을 따르기만 한다고 해서 날짜 표기 형식 문제가 모두 해결되는 것은 아니다. 시스템에서 제공하는 날짜 표기 형식이 실제로 해당 국가에서 오류라고 생각할 수도 있고, 입력 시 사용자의 실수로 인한 혼동도 무시 못한다.

그래서 국제화가 잘 된 소프트웨어에서는 날짜 형식에 대해서 조금 더 고민을 해야 한다. 우선 날짜를 출력하는 방법은 크게 3가지가 있다. 각각 장단점이 있다.

첫 번째 지난번 12회에서 봤듯이 로케일별로 각각 다른 날짜 형식으로 출력을 하는 것이다. OS나 개발툴, 라이브러리에 따라서 그 형식이 조금씩은 다르지만 웬만큼은 현지에서 받아들여 질만한 형식을 제공한다. 장점으로는 개발자가 날짜 형식을 직접 연구하고 다루지 않기 때문에구현이 상대적으로 간단하다. 하지만 단점으로는 라이브러리나 프레임워크에 따라서 제공하는 포맷이 일정하지 않고 원하는 날짜 형식을 제대로 제공하지 못할 수도 있다. 또한 그렇게 제공한 날짜 형식에 버그가 있을 경우 개별적으로 수정을 해야 하는 번거로움이 있다.
C에서는 strftime()함수를 사용하거나 QT Framework에서는 QDate::toString() 함수를 이용할 수 있다. 




두 번째사용자가 날짜 형식을 선택하거나 직접 입력하도록 하는 방식이다. 개발자가 완벽하게 사용자가 원하는 날짜 포맷을 제공하는 데는 한계가 있다고 생각하고 그 책임을 사용자에게 맡기는 것이다. 예를 들어 yyyy/MM/dd 라고 지정을 하면 2015/05/27이라고 출력을 할 것이다. 유독 월을 표시하는 M만 대문자인 이유는 분을 표시하는 m(minute)와 구분하기 위해서이다. 이 경우에도 요일과 월은 숫자가 아니라 문자로 표시를 할 수 있으므로 똑 같은 형식이라도 로케일별로 다르게 표시가 된다. 
소프트웨어에서 몇 가지 날짜 형식을 보여주고 사용자가 고르는 방법도 있고 사용자가 완전히 자유롭게 형식을 편집할 수 있도록 할 수도 있다. 물론 고르는 방법이 구현도 편하고 좀더 안전하다. 이 방법의 장점은 개발자가 각 나라의 날짜 형식에 대해서 너무 고민할 필요가 없는 것이다. 단점으로는 사용자가 뭔가 선택을 해야 하는 불편함이 있고, 사용하는 개발언어나 라이브러리에 따라서 날짜 포맷 표기법이 조금씩 다르다는 것이다.
그래서 첫 번째 방법과 두 번째 방법을 섞어서 사용하기도 한다.




세 번째국제 날짜 형식 표준을 이용하는 방법이다. 국제화된 소프트웨어를 개발할 때는 항상 날짜 표시 문제가 있다. 그래서 1988년도에 국제 날짜 표준 형식이 제안되었고, ISO8601이 발표되었다. ISO8601에서는 여러 가지 날짜와 시간의 표준 형식을 다루고 있다. 먼저 국제 날짜 표준 형식은 어떤 것인지 보자.
날짜는 2015-05-28과 같이 YYYY-MM-DD의 형식을 따르고 있다. 연도가 뒤에 있을 경우에는 앞에 온 숫자가 월일지 일일지 헷갈리지만 연도가 맨 앞에 오면 전세게 거의 모든 사람들이 연-월-일로 인식을 한다. 물론 예외는 있을 것이다. 이런 국제 날짜 표준 형식은 우리나라에서 흔히 사용하는 형식이라서 다행이다. 
시간과 같이 표시를 할 때는 2015-05-28T09:15:52와 같이 중간에 “T”를 넣어서 표시한다. Time Zone을 포함해서 2015-05-28T09:15:52+09:00과 같이 표시하는 방법도 있다. 기간을 표시하기 위해서 우리는 흔히 ‘~’를 사용하는데 ISO8601에서는 ‘/’를 사용한다. 2015-05-28/2015-06-28과 같이 표시한다.
이렇게 국제 표준 날짜 형식을 사용하면 소프트웨어를 개발하기 매우 편리하다. 나라별, 로케일 별로 고민을 할 필요가 없고 이로 인한 혼란이나 버그가 거의 없다. 하지만 고집이 센 나라에서 받아들여지지 않고 버그로 보고가 될 수도 있는 단점이 존재한다.

위의 모든 경우에 입력의 문제는 여전히 존재한다. 국제화가 잘된 소프트웨어에서도 흔히 날짜 입력의 문제를 해결하지 못하는 경우가 많다. 날짜 출력은 그 나라의 문화에 알맞게 지원을 하는데 날짜 입력에서 제대로 된 형식을 지원하지 못하는 경우도 흔하다. 또한 날짜 입력은 사용자의 실수를 무시할 수 없다. 그래서 날짜는 날짜 선택기 위젯 같은 것을 이용해서 마우스 클릭을 통해서 사용자가 날짜를 선택하게 하는 UI를 제공하는 것이 좋다. 물론 날짜 선택기가 그레고리력만 제공하는지 그 외의 달력도 제공하는지 이슈가 있기는 하다. 또한 날짜 선택기도 지역화를 제공해야 한다.




위에서 어떤 방식을 제공할지는 소프트웨어의 성격 및 회사의 전략에 따라서 달라질 수가 있다. 단, 일단 개발을 해 놓고 문제가 있다고 고치기 시작하면 이미 좀 늦은 것이다. 사전에 국제화 전략을 정해서 제대로 적용하는 것이 가장 효율적인 방법이다.

멀티유저 국제화 소프트웨어 만드는 방법 (13)

소프트웨어 아키텍처는 창의력의 산물이기 때문에 정답이 있는 것은 아니지만 몇 가지 소개를 하려고 한다. 다시 한번 강조하지만 국제화가 잘 된 소프트웨어의 아키텍처 원칙은 다음과 같다.

“하나의 소스코드, 한번의 빌드, 하나의 팩키지”




나라별로 별도의 소스코드를 관리하고 별도로 빌드를 하거나 제품이 각각 따로 나온다면 이를 관리하기 위해서 열배, 백배의 노력을 들여야 한다.

국제화된 소프트웨어는 크게 “싱글 로케일”과 “멀티 로케일”로 구분할 수 있다. “싱글 로케일”은 소프트웨어가 동작하면서 하나의 로케일만 지원하는 것이다. 이런 소프트웨어는 지원하는 로케일을 바꾸려면 소프트웨어의 설정을 바꾼 후 Restart 하거나 L10n 모듈을 Reload 해야 한다. 몇몇 데스크탑 소프트웨어가 여기에 해당한다.




 위 그림처럼 어플리케이션이 시작될 때 필요한 L10n 모듈만 Load해서 하나의 로케일로만 동작하는 것이다. 이 경우 L10n 모듈은 DLL이나Shared Object 형태로 제작해서 Dynamic load를 할 수 있다. 이런 아키텍처는 복잡도가 낮고 필요한 L10n 모듈만 Load를 하기 때문에 메모리를 절약할 수 있는 장점이 있다.

아래 그림처럼 한국인이 사용할 때는 L10n ko_KR 라이브러리만 Load를 하고 일본인이 사용할 때는 L10n ja_JP 라이브러리를 Load하면 된다. 이런 방식은 로케일을 중간에 바꾸거나 섞어서 사용할 수 없는 단점이 있다. 예를 들어서 날짜는 한국식으로 표현을 하다가 독일인에게 메시지를 보내기 위해서 숫자의 형식을 바꿔준다든지 하는 등의 기능은 구현할 수 없다. 소프트웨어의 성격에 알맞게 아키텍처를 선택하면 된다.

 

두번째 방식을 “멀티 로케일”을 지원하기 위한 방식이다. “멀티 로케일”은 소프트웨어가 동시에 여러 가지 로케일을 지원하는 것이다. 여러 L10n 라이브러리를 모두 Load 해 놓고 한국인이 사용할 때는 L10n ko_KR 라이브러리를 이용해서 한국인에게 알맞게 동작하고 일본인이 사용할 때는 L10n ja_JP 라이브러리를 사용하는 방식이다. 대부분의 서버 소프트웨어는 “멀티 로케일”지원이 필요하다. 데스크탑 소프트웨어도 요구사항에 따라서 멀티 로케일지원이 필요하다. 사용자가 접속할 때마다 필요한 L10n 라이브러리를 Load하는 것은 부담이 심하기 때문에 모두 Load를 해 놓는 것이다. 
 

“멀티 로케일”을 지원하는 소프트웨어는 한 화면에서 로케일을 바꿔가면서 동작할 수도 있고 기능별로 다른 로케일을 사용할 수도 있다. 즉, 날짜는 한국식, 숫자는 독일식, 통화는 미국식으로 동작하게 할 수도 있다. 이런 소프트웨어는 메모리를 많이 쓰는 단점이 있기는 하지만 메모리를 많이 사용하는 것은 요즘 세상에 단점으로 볼 수도 없다. 장점으로는 소프트웨어 국제화 지원에 제한이 없다는 것이다. 

그럼 이런 방식을 구현하기 위해서는 어떤 아키텍처를 사용해야 할까? 수많은 방법이 있겠지만 그 중에서 한가지 방법은 아래와 같이 클래스 상속을 이용하는 방법이다. L10n Base Class에서 필요한 국제화 함수들을 정의하고 기본 기능을 구현한 후에 각 로케일별 서브클래스를 구현하는 방식이다. 로케일별로 각기 다른 기능은 서브클래스에서 각각 구현하면 된다. 그리고 접속한 사용자에 따라서 필요한 로케일의 서브클래스를 호출하면 된다. 이때 i18n 라이브러리는 적절한 분기를관장하게 된다.


 이 방법 외에도 Function Pointer를 이용하는 방법도 있고 방법은 무궁무진할 것이다. 소프트웨어의 성격에 맞게 창의력을 발휘해서 가장 알맞은 방법을 선택하면 될 것이다. 

소프트웨어를 개발할 때 아키텍처를 결정하는 것은 매우 중요하다. 한번 정하면 쉽게 바꾸기 어렵기 때문이다. 소프트웨어의 전략, 비전 그리고 회사의 목표와 방향도 알아야 소프트웨어의 아키텍처를 잘 정할 수 있다. 국제화된 소프트웨어를 개발할 때는 회사의 국제화 전략을 잘 이해해야 한다. 

목표와 비전을 모르고 후다닥 만들어진 소프트웨어는 십리도 못가서 발병이 날 것 이다. 이런 소프트웨어는 아니 만드니 만도 못한 경우가 허다하다.

01/02/03는 며칠일까? (12)

오늘은 날짜 표기에 대해서 다뤄보자. 날짜 표기 형식도 나라마다 다르다. 그런데 많은 소프트웨어들이 국가별, 로케일별로 다른 날짜 표기 형식을 제대로 처리하지 않아서 특정 국가에서 불만이 커지거나 잘못 사용되는 사례도 빈번하게 발생한다. 심지어는 날짜 표기를 제대로 고려한 소프트웨어에서도 입력의 복잡함과 모호함으로 문제가 발생하곤 한다. 국제화된 소프트웨어를 개발하는 개발자라면 날짜 형식을 다루는 지식과 노하우는 어느 정도 보유해야 한다.







우선 01/02/03은 무엇으로 보이는가? 물론 이런 날짜 형식은 애초에 모호함 때문에 잘 사용하지 않는다. 하지만 꼭 날짜를 이렇게 표현한다면 어떻게 보일까? 100%는 아니지만 미국, 호주, 한국 사람들은 각각 다른 날짜로 읽는 것이 일반적이다.

미국 사람들은 2003년 1월 2일로 볼 것이다. 물론 미국에는 워낙 많은 민족이 있어서 다르게 볼 수도 있지만 대체로 그렇다는 것이다. 호주 사람들은 2003년 2월 1일로 볼 것이다. 하지만 알다시피 한국사람들은2001년 2월 3일로 볼 것이다. 2002년으로 읽는 나라가 없다는 것은 그나마 다행이다.

추가로 그레고리력을 사용하느냐 다른 달력을 사용하느냐에 따라 다른 부분도 있다. 참고로 북한은 주체연호를 사용하고 일본과 태국도 다른 달력을 혼용한다. 이 주제는 따로 다루겠다.




그럼 국가별, 로케일별로 날짜 형식은 어떻게 되면 소프트웨어를 개발할 때 이를 어떻게 다뤄야 하는지 알아보자.

우리가 날짜를 표시하는 방법은 수십 가지가 넘는다. 연도만해도 두자리 또는 네자리로 사용하고 요일도 “월” 또는 “월요일”이라고 쓴다. 영어에서는 월을 표기할 때 “Aug” 또는 “August”로 표기를 한다. 시간까지 같이 표시할지 여부와 시간의 표시 형식까지 합하면 크게 나눠도 열 가지는 넘는다. 소프트웨어를 설계할 때는 소프트웨어의 성격에 따라서지원해야 할 날짜 형식을 표준화해야 한다. 개발자들이 멋대로 여러 가지 날짜 형식을 사용하게 되면 관리가 제대로 안된다. 나중에 버그가 발견되면 수많은 소스코드를 고쳐야 한다. 표준화된 날짜 함수를 제공해서 개발자에게 제공해야 하고 개발자들은 정해진 날짜 함수만 사용해야 한다.

날짜 함수는 입력, 출력 두가지 형태의 함수를 제공해야 한다. 입력은 문자열을 날짜 데이터로 변환하는 것이고 출력은 날짜 데이터를 문자열로 변환하는 함수다. 예를 들어 StrToDate(), DateToStr() 이런 함수를 만들면 된다. 날짜의 형식은 가장 먼저 긴 형식과 짧은 형식을 제공한다. 이는 소프트웨어마다 다르니 개발자가 정해야 한다.



국가별 로케일별로 서로 다른 날짜 형식만 살펴보도록 하자. 먼저 긴 날짜 형식은 어떻게 될까? 우선 로케일별 국가 이름을 소개한다.

ar_SA : 사우디아라비아
de_DE : 독일
en_US : 미국
es_ES : 스페인
fr_FR : 프랑스
id_ID : 인도네시아
it_IT : 이탈리아
ja_JP : 일본
ko_KR : 대한민국
pl_PL : 폴란드
pt_PT : 포르투갈
ru_RU : 러시아
vi_VN : 베트남
zh_CN : 중국
zh_TW : 타이완
de_LI : 리히텐슈타인
th_TH : 태국

로케일(국가)별 긴 날짜 형식은 다음과 같다.

ar_SA : "الاثنين، ١٨ مايو، ٢٠١٥"
de_DE : "Montag, 18. Mai 2015"
en_US : "Monday, May 18, 2015"
es_ES : "lunes 18 de mayo de 2015"
fr_FR : "lundi 18 mai 2015"
id_ID : "Senin, 18 Mei 2015"
it_IT : "lunedì 18 maggio 2015"
ja_JP : "2015年5月18日月曜日"
ko_KR : "2015년 5월 18일 월요일"
pl_PL : "poniedziałek, 18 maja 2015"
pt_PT : "Segunda-feira, 18 de Maio de 2015"
ru_RU : "понедельник, 18 мая 2015 г."
vi_VN : "Thứ hai, ngày 18 tháng năm năm 2015"
zh_CN : "2015年5月18日星期一"
zh_TW : "2015年5月18日星期一"
de_LI : "Montag, 18. Mai 2015"
th_TH : "วันจันทร์ที่ 18 พฤษภาคม 2015"

그럼 짧은 날짜 형식은 국가별, 로케일별로 어떻게 출력될까? 

ar_SA : "١٨‏/٥‏/٢٠١٥"
de_DE : "18.05.15"
en_US : "5/18/15"
es_ES : "18/05/15"
fr_FR : "18/05/15"
id_ID : "18/05/15"
it_IT : "18/05/15"
ja_JP : "2015/05/18"
ko_KR : "15. 5. 18."
pl_PL : "18.05.2015"
pt_PT : "18/05/15"
ru_RU : "18.05.15"
vi_VN : "18/05/2015"
zh_CN : "15-5-18"
zh_TW : "15/5/18"
de_LI : "18.05.15"
th_TH : "18/5/2015"

물론 위 날짜 형식 모두다 정답이 아닐 수도 있다. 필자가 특정 Framework을 사용해서 출력된 결과를 표시한 것뿐이다. 해당 Framework의 국제화 개발팀에서 적절하지 않는 날짜 형식을 구현해 놓았을 수도 있다. 특히, 한국의 짧은 날짜 형식은 마음에 들지 않는다. 하지만 일단 Framework이나 시스템에서 제공하는 날짜 형식을 믿고 개발해야 한다. 개발자가 국가별, 로케일별 날짜 포맷을 직접 연구할 수는 없다. 추후 버그가 보고 될 경우 수정은 할 수 있겠다.

필자가 테스트를 해본 결과 같은 C언어를 쓴다고 하더라도 C언어에서 제공하는 strftime()함수만 하더라도 Microsoft C와 gcc가 제공하는 날짜 형식이 다르다. 이는 OS나 개발툴 개발사마다 날짜 형식을 미묘하게 다르게 제공하고 있다는 것을 알아야 한다. 크로스 플랫폼 개발자는 더욱 유념해서 개발을 해야 한다.

위에서 예로든 두가지 형식 외에도 여러 가지 중간 길이의 날짜 형식이 필요하다. 이런 형식을 제공하기 위해서는 개발자가 날짜 형식에 대해서 조금 더 연구를 해야 한다. 기본 날짜 함수 제공은 쉽지만 여러 가지 형식을 제대로 제공하려면 점점 어려워진다. 소프트웨어 성격에 알맞게 제공할 날짜 포맷을 연구해서 국제화 라이브러리에 추가를 해야 한다.

다음에는 날짜를 다루는 방법을 조금 더 보겠다.