로케일(Locale)이란
로케일(Locale)에 관하여...
- 로케일(Locale)의 의미
- 로케일 설정방법
- 로케일을 지원하기 위한 방법 및 작동 원리
세계 여러 나라들은 각자 다른 문화(언어, 날짜, 시간 등)을 갖고 있다. 프로그램의
국제화(Internationalization, 줄여서 i18n)는 사용자로 하여금 프로그램 수행시
로케일이란 것에 의해 입맛에 맞는 환경을 선택할 수 있도록 만든 것을 말한다.
예를 들어 어떤 프로그램의 메시지가 여러가지 언어로 주어져 있는 경우 이중에
어떤 언어의 것을 출력할 것인가를 사용자가 결정할 수 있는 것이다. 그것을
가능하게 해 주는 수단이 바로 로케일이다. 이것은 단순히 메시지 뿐만이 아니고
숫자표현법, 날짜 또는 시간표현법 등 여러가지에 사용될 수 있다. 그것 각각을
우리는 카테고리(category)라고 부른다. 카테고리에는 LC_COLLATE, LC_CTYPE,
LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME 가 있다.
로케일을 지원하는 프로그램의 실행 방식을 선택하기 위해서는 환경 변수 설정을
이용한다. (카테고리 각각에 해당하는 환경변수는 카테고리 이름과 동일하다.)
로케일 환경 변수에 관한 정보는 locale이란 명령으로 간단히 얻을 수 있다.
% locale
LANG=ko_KR.eucKR
LC_CTYPE="ko_KR.eucKR"
LC_NUMERIC="ko_KR.eucKR"
LC_TIME="ko_KR.eucKR"
LC_COLLATE="ko_KR.eucKR"
LC_MONETARY="ko_KR.eucKR"
LC_MESSAGES="ko_KR.eucKR"
LC_ALL=
위에서 ko_KR.eucKR은 로케일 값(locale name)이다. 일반적인 로케일 값의 형식은
ll[_CC[.EEEE]][@dddd] 이다. ll은 언어(language)를 지정하는 소문자 두 글자 ISO
639 language code, CC는 지역(territory)를 지정하는 대문자 두 글자 ISO 3166
country code, EEEE는 코드셋(codeset)을 지정하는 문자셋(character set) 또는
인코딩(encoding), dddd는 방언 등의 변종을 구별하기 위한 것(modifier)이다. []로
표시된 내용은 안 쓸수도 있음을 의미한다. 예를 들면 en_US는 미국 영어권, en_CA는
영어권 카나다, de_DE는 독일의 독일어, fr_FR는 프랑스의 프랑스어를 의미한다.
아무 로케일도 설정하지 않았을 때 glibc에서의 기본 로케일은 C 또는 POSIX
(glibc에서는 C 로케일의 alias) 로케일이다.
% locale -a
라는 명령을 이용하면 이외에 사용 가능한 로케일의 이름들을 알 수 있다.
다음은 여러가지 환경변수의 역할(카테고리의 경우에는 동시에 카테고리의 역할)에
관한 설명이다.
LANG : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다. 하지만 LC_*
환경변수보다 우선 순위가 낮다. LC_ALL이 설정이 안 되어 있고 LC_* 값들이 설정이
따로 설정이 않된 경우 LANG을 변화시키면 LC_ALL을 제외한 로케일 카테고리들의
값이 변경되지만 LC_ALL이 설정 되어 있는 경우 LANG의 변화는 로케일 카테고리들의
값에 영향을 주지 않는다.
LC_CTYPE : 문자 분류(알파벳, 숫자, 한글 또는 소문자, 대문자 등등), 변환,
대소문자 비교을 위한 로케일 설정을 의미한다. 이것은 예를 들어 fgetwc(), is*(),
isw*(), mblen(), mbtowc(), wcstombs() 등의 함수에 영향을 줄 수 있다.
LC_COLLATE : 스트링(string)의 정렬 순서(sort order 또는 collation)를 위한
로케일 설정을 위해 사용된다. 이것은 예를 들어 strcoll(), wcscoll(), strxfrm()
등의 함수에 영향을 줄 수 있다.
LC_MESSAGES : 메시지 표현을 위한 로케일 설정. 메시지의 국제화를 위한
catopen(), gettext() 등의 함수에 영향을 줄 수 있다.
LC_NUMERIC : 금액이 아닌 숫자 표현(천단위, 소수점, 숫자 그룹핑 등)을 위한
로케일 설정. 예를 들어 strtod(), atof().
LC_MONETARY : 금액 표현(천단위 구분 문자, 소수점 문자, 금액 표시 문자, 그
위치 등)을 위한 로케일 설정. 예를 들어 strfmon().
LC_TIME : 시간과 날짜의 표현(년, 월, 일에 대한 명칭 등)을 위한 로케일 설정
예를 들어 strftime(), strptime().
LC_ALL : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다. 위의 LC_* 및
LANG의 어떤 것보다 우선 순위가 높다. 그리고 LC_ALL을 설정하면 다른 로케일
카테고리의 값들이 LC_ALL의 값의 변경되고 LC_ALL설정을 없애면 다른 로케일
카테고리의 값들은 이전값을 유지한다.
LANGUAGE : 로케일의 다중 설정을 위해 gettext에서 사용되는 GNU extension
환경변수로 LC_ALL보다도 우선순위가 높다. 로케일들은 구분문자 : 을 이용하여
우선순위가 높은 순대로 나열된다. 예를 들어 LANGUAGE=en_US:ko_KR
LINGUAS : gettext를 사용하는 프로그램 설치시 지정한 언어들의 메시지만을
설치하기 위한 환경변수. 구분 문자는 스페이스이다. 예를 들어 LINGUAS="ko ja"
로케일을 제대로 지원하는 프로그램을 작성하기 위해서는 setlocale()함수를
이용하여 로케일을 설정하고 확인하여야 한다. setlocale()함수는 헤더 파일
locale.h 에 정의되어 있으며 그 프로토타입은 다음과 같다.
char *setlocale (int category, const char *locale);
이 함수의 역할은 카테고리 category에 대해 로케일 locale을 설정하고 (물론, 사용
가능한 로케일인 경우), 설정된 로케일값을 리턴하는 것이다.
locale 부분에 ""을 넣은 다음과 같은 예는
setlocale (LC_ALL, "");
적당한 환경변수를 참조하여 로케일을 설정하고 그 값을 리턴한다. 환경변수를
참조하는 우선순위는 위에서 설명한대로 LC_ALL, 그외 카테고리, LANG변수 순이고,
변수값을 알아내면 locale.alias(예를 들어, /usr/share/locale/)를 참조한 후
뒤에서부터 @ . _ 을 단위로 순서대로 잘라가며 사용가능한 로케일을 찾아낸다.
인수 locale 부분에 NULL을 넣은 다음예는
locale = setlocale (LC_ALL, NULL);
로케일 값을 변경시키지 않고 단지 카테고리에 관한 현재 로케일값을 알아내고자
하기 위해 그 리턴값을 사용하는 예이다.
다음은 함수 setlocale()을 사용하여 임시로 로케일로 변경하는 예이다. (glibc
manual에 있는 예)
#include <stddef.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
void
with_other_locale (char *new_locale,
void (*subroutine) (int),
int argument)
{
char *old_locale, *saved_locale;
/* 현재 로케일명을 알아낸다. */
old_locale = setlocale (LC_ALL, NULL);
/* setlocale()의 재호출 의해 변경될 것을 대비해 로케일 이름을 미리 복사해 둔다. */
saved_locale = strdup (old_locale);
if (saved_locale == NULL)
fatal ("Out of memory");
/* 로케일을 변경하고 subroutine을 수행한다. */
setlocale (LC_ALL, new_locale);
(*subroutine) (argument);
/* 원래의 로케일로 복귀한다. */
setlocale (LC_ALL, saved_locale);
free (saved_locale);
}
다음은 로케일을 이용하여 날짜/시간을 출력하는 프로그램의 예이다.
#include <stdio.h>
#include <locale.h>
#include <time.h>
int main(void)
{
time_t now;
struct tm *l_time;
char string[256];
/* 환경변수로부터 시간 관련 로케일을 결정한다. */
setlocale(LC_TIME, "");
/* calendar 시간을 now라는 변수에 저장.
* 그 값은 1970년 1월 1일 이후부터 지금까지의 초단위 시간 */
now = time((time_t *)NULL);
/* calendar 시간의 다른 유용한 형태를 l_time변수에 저장 */
l_time = localtime(&now);
/* 우리가 원하는 포맷의 시간 포맷을 string이라는 변수에 저장 */
strftime(string, sizeof string, "%c", l_time);
/* 출력 */
printf("%s\n", string);
return 0;
}
다음은 위의 파일을 time_test.c라고 저장하고 컴파일하여 c쉘에서 시험하는
예이다.
% gcc -o time_test time_test.c
% setenv LANG ko_KR.eucKR
% ./time_test
2000년 01월 12일 수요일 오후 10시 26분 56초
% setenv LANG C
% ./time_test
Wed Jan 12 22:27:22 2000
최근의 RHEL이나 CentOS 의 기본 locale 은 utf8 이지만 예전 Linux나 AIX나 HP-UX 등의 OS init.d/script 를 보면 다음과 같은 부분이 있는 경우가 있다.
그간 application이 한글 메시지를 출력할 때 터미널이 한글을 지원 못해 깨져 보일 경우 무의식적으로 export LANG=C 를 입력하여 해결했는데 이게 정확히 무슨 의미인지, C가 맞는 locale 인지, 왜 D 나 E 가 아니라 C 인지 궁금해서 찾아보았다.
결론은 LANG 을 "C" 로 설정하는건 locale 을 끄는 의미이고 "C" 는 표준에 있는 locale name 이 맞다고 한다.
locale name 이 "C" 인것은 C 언어 표준중 7.11.1.1 The setlocale function 에 다음과 같이 지정되어 있기때문이다. (C 언어 표준에 있는 내용이라 "C" 인것 같다)
Why “LANG=C”? (not D or E or F)
In order to turn off localisation features one should set LANG environment variable to "C".
Why "C"? Where it came from?
In the C programming language, the locale name C
“specifies the minimal environment for C translation” (C99 §7.11.1.1; the principle has been the same since at least the 1980s). As most operating systems are written in C, especially the Unix-inspired ones where locales are set through the LANG
and LC_xxx
environment variables, C
ends up being the name of a “safe” locale everywhere.
POSIX specifies that both C
and POSIX
must be valid locale names, with the same neutral settings.
source - http://superuser.com/questions/219945/why-lang-c-not-d-or-e-or-f
1. Locale
Locale(로케일은) 프로그램을 언어와 국가에 최적화하기 위해서 사용하는 "지역/언어"정보다. 프로그램은 유저(보통 시스템 관리자)가 설정한 locale에 따라서, 입/출력 인코딩을 적용해서 메시지를 출력한다.
로케일관련 패키지는 locales이고, 보조적으로 각 언어별로 language-pack-*패키지가 있다.
2. Locale 목록 확인
locale -a로 운영체제에서 사용할 수 있는 로케일 정보를 볼 수 있다.
3. 현재 로케일 정보 확인하기
locale명령으로 시스템의 로케일 정보를 확인할 수 있다.
LANG | LC_* 값들을 설정하지 않았을 때 적용되는 기본 값 |
LC_ADDRESS | |
LC_ALL | LC_ALL의 값으 LC_*의 값이 override 된다. |
LC_TIME | 시간 출력 양식 설정 |
LC_TELEPHONE | 전화번호의 출력 양식 설정 |
LC_PAPER | 종이의 크기 형식. 11 x17 inches, A4 등등 |
LC_NUMBER | 숫자표현양식. 대부분 소수구분으로 "."을 사용하지만, 어떤 나라는 ","을 사용한다. |
LC_NAME | 이름 표기 형식. first, last name등 |
LC_MESSAGES | 시스템 메시지 출력에 사용할 언어 |
LC_CTYPE | 대문자, 소문자간의 변환 형식 |
LC_COLLATE | 알파벳의 정렬과 관련된 규칙. "C"나 "POSIX" 로케일의 경우 strcmp()를 적용한 것과 같은 결과를 보인다. |
4. 로케일별 출력 예제
로케일 관련된 환경변수 설정에 따른 출력 결과
5. 로케일 설정 변경
시스템 기본 로케일 설정은 /etc/default/locale을 수정하면 된다.
6. 로케일 생성
VirtualBox로 Ubuntu 13.04 server 운영체제를 설치했다. 그런데 로케일에 ko_KR.utf8이 설치가 안됐다. 아마도 설치하면서 언어설정을 기본(영어)로 했기 때문인 것 같다. 종종 이런 경우를 경험한다. 특히 AWS에서 리눅스 인스턴스를 올린 후에는 거의 반드시 로케일 설정을 해줘야 한다.
ko_KR.utf8 로케일을 추가해 보자.
이제 /etc/default/locale를 수정하는 것으로 기본 로케일 설정을 변경할 수 있다.
혹은 (bash를 사용한다면).bash_profile을 수정하는 방법도 있다.