"gettext" --- 다국어 국제화 서비스
**********************************

**소스 코드:** Lib/gettext.py

======================================================================

"gettext" 모듈은 파이썬 모듈과 응용 프로그램을 위한 국제화(I18N)와 현
지화(L10N) 서비스를 제공합니다. GNU **gettext** 메시지 카탈로그 API와
파이썬 파일에 더 적합한 고수준 클래스 기반 API를 모두 지원합니다. 아래
설명된 인터페이스를 사용하면 모듈과 응용 프로그램 메시지를 하나의 자연
어로 작성하고, 다른 자연어로 실행하기 위해 번역된 메시지 카탈로그를 제
공할 수 있습니다.

파이썬 모듈과 응용 프로그램을 현지화하는 데 대한 힌트도 제공됩니다.


GNU **gettext** API
===================

"gettext" 모듈은 GNU **gettext** API와 매우 유사한 다음 API를 정의합니
다. 이 API를 사용하면 전체 응용 프로그램의 번역에 전역적으로 영향을 미
칩니다. 응용 프로그램이 단일 언어라면 사용자의 로케일에 따라 언어를 선
택할 수 있는 것과 함께 종종 이것이 여러분이 원하는 것입니다. 파이썬 모
듈을 현지화하거나, 응용 프로그램에서 언어를 실행 중에 전환해야 한다면,
아마도 클래스 기반 API를 대신 사용하고 싶을 것입니다.

gettext.bindtextdomain(domain, localedir=None)

   *domain*을 로케일 디렉터리 *localedir*에 바인드합니다. 보다 구체적
   으로, "gettext"는 경로 (유닉스에서)
   "*localedir*/*language*/LC_MESSAGES/*domain*.mo"를 사용하여 지정된
   도메인(domain)에 대한 바이너리 ".mo" 파일을 찾습니다. 여기서
   *language*는 환경 변수 "LANGUAGE", "LC_ALL", "LC_MESSAGES" 및
   "LANG"에서 각각 검색됩니다.

   *localedir*이 생략되거나 "None"이면, *domain*에 대한 현재 바인딩이
   반환됩니다. [1]

gettext.textdomain(domain=None)

   현재 전역 도메인을 변경하거나 조회합니다. *domain*이 "None"이면, 현
   재 전역 도메인이 반환되고, 그렇지 않으면 전역 도메인이 *domain*으로
   설정되어 반환됩니다.

gettext.gettext(message)

   Return the localized translation of *message*, based on the current
   global domain, language, and locale directory.  This function is
   usually aliased as "_()" in the local namespace (see examples
   below).

gettext.dgettext(domain, message)

   "gettext()"와 비슷하지만, 지정된 *domain*에서 메시지를 찾습니다.

gettext.ngettext(singular, plural, n)

   "gettext()"와 비슷하지만, 복수형(plural forms)을 고려합니다. 번역이
   발견되면, 복수 공식을 *n*에 적용하고, 결과 메시지를 반환합니다 (일
   부 언어는 복수형이 두 개 이상입니다). 번역이 없으면, *n*이 1이면
   *singular*를 반환합니다; 그렇지 않으면 *plural*을 반환합니다.

   복수 공식은 카탈로그 헤더에서 취합니다. 자유 변수 *n*을 갖는 C나 파
   이썬 표현식입니다. 이 표현식은 카탈로그에서 복수의 인덱스로 평가됩
   니다. ".po" 파일에 사용되는 정확한 문법과 다양한 언어의 공식은 GNU
   gettext 설명서를 참조하십시오.

gettext.dngettext(domain, singular, plural, n)

   "ngettext()"와 비슷하지만, 지정된 *domain*에서 메시지를 찾습니다.

gettext.pgettext(context, message)

gettext.dpgettext(domain, context, message)

gettext.npgettext(context, singular, plural, n)

gettext.dnpgettext(domain, context, singular, plural, n)

   접두사에 "p"가 없는 해당 함수(즉, "gettext()", "dgettext()",
   "ngettext()", "dngettext()")와 유사하지만, 번역은 지정된 메시지
   *context*로 제한됩니다.

   버전 3.8에 추가.

Note that GNU **gettext** also defines a "dcgettext()" method, but
this was deemed not useful and so it is currently unimplemented.

이 API의 일반적인 사용 예는 다음과 같습니다:

   import gettext
   gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
   gettext.textdomain('myapplication')
   _ = gettext.gettext
   # ...
   print(_('This is a translatable string.'))


클래스 기반 API
===============

The class-based API of the "gettext" module gives you more flexibility
and greater convenience than the GNU **gettext** API.  It is the
recommended way of localizing your Python applications and modules.
"gettext" defines a "GNUTranslations" class which implements the
parsing of GNU ".mo" format files, and has methods for returning
strings. Instances of this class can also install themselves in the
built-in namespace as the function "_()".

gettext.find(domain, localedir=None, languages=None, all=False)

   이 함수는 표준 ".mo" 파일 검색 알고리즘을 구현합니다.
   "textdomain()"이 취하는 것과 동일한 *domain*을 취합니다. 선택적
   *localedir*은 "bindtextdomain()"에서와 같습니다. 선택적 *languages*
   는 문자열 리스트이며, 각 문자열은 언어 코드입니다.

   *localedir*이 제공되지 않으면, 기본 시스템 로케일 디렉터리가 사용됩
   니다. [2] *languages*가 제공되지 않으면, 다음과 같은 환경 변수가 검
   색됩니다: "LANGUAGE", "LC_ALL", "LC_MESSAGES" 및 "LANG". 비어 있지
   않은 값을 반환하는 첫 번째 것이 *languages* 변수에 사용됩니다. 환경
   변수는 콜론으로 구분된 언어 목록을 포함해야 하며, 콜론에서 분할되어
   예상되는 언어 코드 문자열 리스트를 생성합니다.

   그런 다음 "find()"는 언어를 확장하고 정규화한 다음, 다음 구성 요소
   로 구성된 기존 파일을 검색하면서, 이들을 이터레이트 합니다:

   "*localedir*/*language*/LC_MESSAGES/*domain*.mo"

   존재하는 첫 번째 파일 이름이 "find()"에 의해 반환됩니다. 그러한 파
   일이 없으면, "None"이 반환됩니다. *all*이 제공되면, 언어 리스트나
   환경 변수에 나타나는 순서대로 모든 파일 이름의 리스트를 반환합니다.

gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False)

   Return a "*Translations" instance based on the *domain*,
   *localedir*, and *languages*, which are first passed to "find()" to
   get a list of the associated ".mo" file paths.  Instances with
   identical ".mo" file names are cached.  The actual class
   instantiated is *class_* if provided, otherwise "GNUTranslations".
   The class's constructor must take a single *file object* argument.

   여러 파일이 발견되면, 이후 파일은 이전 파일에 대한 폴 백으로 사용됩
   니다. 폴 백을 설정하는 것을 허락하기 위해, "copy.copy()"를 사용하여
   캐시에서 각 번역 객체를 복제합니다; 실제 인스턴스 데이터는 여전히
   캐시와 공유됩니다.

   ".mo" 파일이 없으면, 이 함수는 *fallback*이 거짓(기본값)이면
   "OSError"를 발생시키고, *fallback*이 참이면 "NullTranslations" 인스
   턴스를 반환합니다.

   버전 3.3에서 변경: "IOError" used to be raised, it is now an alias
   of "OSError".

   버전 3.11에서 변경: *codeset* parameter is removed.

gettext.install(domain, localedir=None, *, names=None)

   This installs the function "_()" in Python's builtins namespace,
   based on *domain* and *localedir* which are passed to the function
   "translation()".

   *names* 매개 변수에 대해서는, 번역 객체의 "install()" 메서드에 대한
   설명을 참조하십시오.

   As seen below, you usually mark the strings in your application
   that are candidates for translation, by wrapping them in a call to
   the "_()" function, like this:

      print(_('This string will be translated.'))

   For convenience, you want the "_()" function to be installed in
   Python's builtins namespace, so it is easily accessible in all
   modules of your application.

   버전 3.11에서 변경: *names* is now a keyword-only parameter.


"NullTranslations" 클래스
-------------------------

번역 클래스는 원본 소스 파일 메시지 문자열을 번역된 메시지 문자열로 실
제로 구현합니다. 모든 번역 클래스에서 사용하는 베이스 클래스는
"NullTranslations"입니다; 여러분 자신의 특수화된 번역 클래스를 작성하
는 데 사용할 수 있는 기본 인터페이스를 제공합니다. "NullTranslations"
의 메서드는 다음과 같습니다:

class gettext.NullTranslations(fp=None)

   베이스 클래스에서 무시되는, 선택적인 *파일 객체* *fp*를 취합니다.
   파생 클래스에 의해 설정되는 "보호되는" 인스턴스 변수 *_info*와
   *_charset* 뿐만 아니라 "add_fallback()"을 통해 설정되는 *_fallback*
   을 초기화합니다. 그런 다음 *fp*가 "None"이 아니면 "self._parse(fp)"
   를 호출합니다.

   _parse(fp)

      베이스 클래스에서 아무런 일도 하지 않는 이 메서드는 파일 객체
      *fp*를 취하고, 이 파일에서 데이터를 읽고, 메시지 카탈로그를 초기
      화합니다. 지원되지 않는 메시지 카탈로그 파일 형식이 있으면, 이
      메서드를 재정의하여 형식을 구문 분석해야 합니다.

   add_fallback(fallback)

      현재 번역 객체의 폴 백 객체로 *fallback*을 추가합니다. 주어진 메
      시지에 대한 번역을 제공할 수 없으면 번역 개체는 폴 백을 참조해야
      합니다.

   gettext(message)

      폴 백이 설정되었으면, "gettext()"를 폴 백으로 전달합니다. 그렇지
      않으면, *message*를 반환합니다. 파생 클래스에서 재정의됩니다.

   ngettext(singular, plural, n)

      폴 백이 설정되었으면, "ngettext()"를 폴 백으로 전달합니다. 그렇
      지 않으면, *n*이 1이면 *singular*를 반환합니다; 그렇지 않으면
      *plural*을 반환합니다. 파생 클래스에서 재정의됩니다.

   pgettext(context, message)

      폴 백이 설정되었으면, "pgettext()"를 폴 백으로 전달합니다. 그렇
      지 않으면, 번역된 메시지를 반환합니다. 파생 클래스에서 재정의됩
      니다.

      버전 3.8에 추가.

   npgettext(context, singular, plural, n)

      폴 백이 설정되었으면, "npgettext()"를 폴 백으로 전달합니다. 그렇
      지 않으면, 번역된 메시지를 반환합니다. 파생 클래스에서 재정의됩
      니다.

      버전 3.8에 추가.

   info()

      Return a dictionary containing the metadata found in the message
      catalog file.

   charset()

      메시지 카탈로그 파일의 인코딩을 반환합니다.

   install(names=None)

      이 메서드는 "gettext()"를 내장 이름 공간에 설치하여, "_"에 연결
      합니다.

      If the *names* parameter is given, it must be a sequence
      containing the names of functions you want to install in the
      builtins namespace in addition to "_()".  Supported names are
      "'gettext'", "'ngettext'", "'pgettext'", and "'npgettext'".

      Note that this is only one way, albeit the most convenient way,
      to make the "_()" function available to your application.
      Because it affects the entire application globally, and
      specifically the built-in namespace, localized modules should
      never install "_()". Instead, they should use this code to make
      "_()" available to their module:

         import gettext
         t = gettext.translation('mymodule', ...)
         _ = t.gettext

      This puts "_()" only in the module's global namespace and so
      only affects calls within this module.

      버전 3.8에서 변경: "'pgettext'"와 "'npgettext'"를 추가했습니다.


"GNUTranslations" 클래스
------------------------

The "gettext" module provides one additional class derived from
"NullTranslations": "GNUTranslations".  This class overrides
"_parse()" to enable reading GNU **gettext** format ".mo" files in
both big-endian and little-endian format.

"GNUTranslations" parses optional metadata out of the translation
catalog. It is convention with GNU **gettext** to include metadata as
the translation for the empty string. This metadata is in **RFC
822**-style "key: value" pairs, and should contain the "Project-Id-
Version" key.  If the key "Content-Type" is found, then the "charset"
property is used to initialize the "protected" "_charset" instance
variable, defaulting to "None" if not found.  If the charset encoding
is specified, then all message ids and message strings read from the
catalog are converted to Unicode using this encoding, else ASCII is
assumed.

Since message ids are read as Unicode strings too, all "*gettext()"
methods will assume message ids as Unicode strings, not byte strings.

The entire set of key/value pairs are placed into a dictionary and set
as the "protected" "_info" instance variable.

".mo" 파일의 매직 번호가 유효하지 않거나, 주 버전 번호가 예상치 못한
값이거나, 파일을 읽는 동안 다른 문제가 발생하면 "GNUTranslations" 클래
스를 인스턴스 화할 때 "OSError"가 발생할 수 있습니다.

class gettext.GNUTranslations

   베이스 클래스 구현에서 다음 메서드가 재정의되었습니다:

   gettext(message)

      카탈로그에서 *message* id를 찾아 해당 메시지 문자열을 유니코드
      문자열로 반환합니다. 카탈로그에 *message* id에 대한 항목이 없고,
      폴 백이 설정되었으면, 조회는 폴 백의 "gettext()" 메서드로 전달됩
      니다. 그렇지 않으면, *message* id가 반환됩니다.

   ngettext(singular, plural, n)

      메시지 id의 복수형 조회를 수행합니다. *singular*는 카탈로그에서
      찾기 위해 메시지 id로 사용되는 반면, *n*은 사용할 복수형을 결정
      하는 데 사용됩니다. 반환된 메시지 문자열은 유니코드 문자열입니다
      .

      카탈로그에서 메시지 id를 찾을 수 없고, 폴 백이 지정되었으면, 요
      청은 폴 백의 "ngettext()" 메서드로 전달됩니다. 그렇지 않으면,
      *n*이 1이면 *singular*가 반환되고, 다른 모든 경우에는 *plural*이
      반환됩니다.

      예를 들면 다음과 같습니다:

         n = len(os.listdir('.'))
         cat = GNUTranslations(somefile)
         message = cat.ngettext(
             'There is %(num)d file in this directory',
             'There are %(num)d files in this directory',
             n) % {'num': n}

   pgettext(context, message)

      카탈로그에서 *context*와 *message* id를 찾아 해당 메시지 문자열
      을 유니코드 문자열로 반환합니다. 카탈로그에 *message* id와
      *context*에 대한 항목이 없고, 폴 백이 설정되었으면, 조회는 폴 백
      의 "pgettext()" 메서드로 전달됩니다. 그렇지 않으면, *message* id
      가 반환됩니다.

      버전 3.8에 추가.

   npgettext(context, singular, plural, n)

      메시지 ID의 복수형 조회를 수행합니다. *singular*는 카탈로그에서
      찾기 위해 메시지 id로 사용되는 반면, *n*은 사용할 복수형을 결정
      하는 데 사용됩니다.

      *context*의 메시지 id가 카탈로그에 없고, 폴 백이 지정되었으면,
      요청은 폴 백의 "npgettext()" 메서드로 전달됩니다. 그렇지 않으면,
      *n*이 1이면 *singular*가 반환되고, 다른 모든 경우에는 *plural*이
      반환됩니다.

      버전 3.8에 추가.


Solaris 메시지 카탈로그 지원
----------------------------

Solaris 운영 체제는 자체 바이너리 ".mo" 파일 형식을 정의하지만, 이 형
식에 대한 설명서를 찾을 수 없어서, 현재 지원되지 않습니다.


Catalog 생성자
--------------

GNOME은 James Henstridge의 "gettext" 모듈 버전을 사용하지만, 이 버전은
API가 약간 다릅니다. 설명된 사용법은 다음과 같습니다:

   import gettext
   cat = gettext.Catalog(domain, localedir)
   _ = cat.gettext
   print(_('hello world'))

For compatibility with this older module, the function "Catalog()" is
an alias for the "translation()" function described above.

이 모듈과 Henstridge 버전의 한 가지 차이점: 그의 카탈로그 객체는 매핑
API를 통한 액세스를 지원했지만, 사용되지 않는 것으로 보여서 현재 지원
되지 않습니다.


프로그램과 모듈의 국제화
========================

국제화(I18N)는 프로그램이 여러 언어를 인식하도록 하는 작업을 말합니다.
현지화(L10N)는 일단 국제화된 프로그램이 현지 언어와 문화적 습관에 적응
하는 것을 말합니다. 파이썬 프로그램에 다국어 메시지를 제공하려면, 다음
단계를 수행해야 합니다:

1. 번역 가능한 문자열을 특별히 표시하여 프로그램이나 모듈을 준비합니다

2. 표시된 파일에 대해 도구 모음을 실행하여 원시 메시지 카탈로그를 생성
   합니다

3. 메시지 카탈로그의 언어별 번역을 만듭니다

4. 메시지 문자열이 올바르게 번역되도록 "gettext" 모듈을 사용합니다

In order to prepare your code for I18N, you need to look at all the
strings in your files.  Any string that needs to be translated should
be marked by wrapping it in "_('...')" --- that is, a call to the
function "_".  For example:

   filename = 'mylog.txt'
   message = _('writing a log message')
   with open(filename, 'w') as fp:
       fp.write(message)

이 예에서, 문자열 "'writing a log message'"는 번역 후보로 표시되지만,
문자열 "'mylog.txt'"와 "'w'"는 그렇지 않습니다.

There are a few tools to extract the strings meant for translation.
The original GNU **gettext** only supported C or C++ source code but
its extended version **xgettext** scans code written in a number of
languages, including Python, to find strings marked as translatable.
Babel is a Python internationalization library that includes a
"pybabel" script to extract and compile message catalogs.  François
Pinard's program called **xpot** does a similar job and is available
as part of his po-utils package.

(파이썬에는 **pygettext.py**와 **msgfmt.py**라고 하는 이러한 프로그램
의 순수 파이썬 버전도 포함되어 있습니다; 일부 파이썬 배포판은 이 프로
그램들을 설치합니다. **pygettext.py**는 **xgettext**와 유사하지만, 파
이썬 소스 코드만 이해하며 C나 C++ 와 같은 다른 프로그래밍 언어를 처리
할 수 없습니다. **pygettext.py**는 **xgettext**와 유사한 명령 줄 인터
페이스를 지원합니다; 사용에 대한 자세한 내용을 보려면, "pygettext.py
--help"를 실행하십시오. **msgfmt.py**는 GNU **msgfmt**와 바이너리 호환
됩니다. 이 두 프로그램을 사용하면, 파이썬 응용 프로그램을 국제화하기
위해 GNU **gettext** 패키지가 필요하지 않을 수 있습니다.)

**xgettext**, **pygettext** 및 유사한 도구는 메시지 카탈로그인 ".po"
파일을 생성합니다. 이 파일은 소스 코드에 표시된 모든 문자열과 이러한
문자열의 번역된 버전에 대한 자리를 포함하는 사람이 읽을 수 있는 파일입
니다.

이 ".po" 파일의 사본은 지원되는 모든 자연어에 대한 번역을 작성하는 개
별 인간 번역가에게 전달됩니다. 완성된 언어별 버전을 "<language-
name>.po" 파일로 다시 보내고, 이는 **msgfmt** 프로그램을 사용하여 기계
가 읽을 수 있는 ".mo" 바이너리 카탈로그 파일로 컴파일됩니다. ".mo" 파
일은 실행 시간에 실제 번역 처리를 위해 "gettext" 모듈에서 사용됩니다.

코드에서 "gettext" 모듈을 사용하는 방법은 단일 모듈을 국제화하는지 또
는 전체 응용 프로그램을 국제화하는지에 따라 다릅니다. 다음 두 섹션에서
는 각 사례에 관해 설명합니다.


모듈 현지화
-----------

모듈을 현지화한다면, 전역적인 변경을 가하지 않도록 주의해야 합니다, 예
를 들어, 내장 이름 공간. GNU **gettext** API 대신 클래스 기반 API를 사
용해야 합니다.

모듈이 "spam"이고 모듈의 다양한 자연어 번역 ".mo" 파일이
"/usr/share/locale"에 GNU **gettext** 형식으로 존재한다고 가정해 봅시
다. 다음은 모듈 맨 위에 들어갈 내용입니다:

   import gettext
   t = gettext.translation('spam', '/usr/share/locale')
   _ = t.gettext


응용 프로그램 현지화
--------------------

If you are localizing your application, you can install the "_()"
function globally into the built-in namespace, usually in the main
driver file of your application.  This will let all your application-
specific files just use "_('...')" without having to explicitly
install it in each file.

간단한 경우에는, 응용 프로그램의 메인 드라이버 파일에 다음 코드만 추가
하면 됩니다:

   import gettext
   gettext.install('myapplication')

로케일 디렉터리를 설정해야 하면, "install()" 함수로 전달할 수 있습니다
:

   import gettext
   gettext.install('myapplication', '/usr/share/locale')


실행 중 언어 변경
-----------------

프로그램에서 동시에 여러 언어를 지원해야 하면, 다음과 같은 식으로 여러
번역 인스턴스를 만든 다음 명시적으로 전환할 수 있습니다:

   import gettext

   lang1 = gettext.translation('myapplication', languages=['en'])
   lang2 = gettext.translation('myapplication', languages=['fr'])
   lang3 = gettext.translation('myapplication', languages=['de'])

   # start by using language1
   lang1.install()

   # ... time goes by, user selects language 2
   lang2.install()

   # ... more time goes by, user selects language 3
   lang3.install()


지연된 번역
-----------

대부분의 코딩 상황에서, 문자열은 코딩된 위치에서 번역됩니다. 그러나 때
때로, 번역을 위해 문자열을 표시하지만, 실제 번역을 뒤로 연기할 필요가
있습니다. 전형적인 예는 다음과 같습니다:

   animals = ['mollusk',
              'albatross',
              'rat',
              'penguin',
              'python', ]
   # ...
   for a in animals:
       print(a)

여기서, "animals" 리스트의 문자열을 번역 가능한 것으로 표시하려고 하지
만, 실제로 인쇄될 때까지 번역하고 싶지는 않습니다.

이 상황을 처리 할 수 있는 한 가지 방법은 다음과 같습니다:

   def _(message): return message

   animals = [_('mollusk'),
              _('albatross'),
              _('rat'),
              _('penguin'),
              _('python'), ]

   del _

   # ...
   for a in animals:
       print(_(a))

This works because the dummy definition of "_()" simply returns the
string unchanged.  And this dummy definition will temporarily override
any definition of "_()" in the built-in namespace (until the "del"
command). Take care, though if you have a previous definition of "_()"
in the local namespace.

Note that the second use of "_()" will not identify "a" as being
translatable to the **gettext** program, because the parameter is not
a string literal.

이를 처리하는 다른 방법은 다음 예제를 사용하는 것입니다:

   def N_(message): return message

   animals = [N_('mollusk'),
              N_('albatross'),
              N_('rat'),
              N_('penguin'),
              N_('python'), ]

   # ...
   for a in animals:
       print(_(a))

In this case, you are marking translatable strings with the function
"N_()", which won't conflict with any definition of "_()". However,
you will need to teach your message extraction program to look for
translatable strings marked with "N_()". **xgettext**, **pygettext**,
"pybabel extract", and **xpot** all support this through the use of
the "-k" command-line switch. The choice of "N_()" here is totally
arbitrary; it could have just as easily been
"MarkThisStringForTranslation()".


감사의 말
=========

다음 분들은 이 모듈을 만드는 데 코드, 피드백, 디자인 제안, 이전 구현
및 귀중한 경험을 제공했습니다:

* Peter Funk

* James Henstridge

* Juan David Ibáñez Palomar

* Marc-André Lemburg

* Martin von Löwis

* François Pinard

* Barry Warsaw

* Gustavo Niemeyer

-[ 각주 ]-

[1] The default locale directory is system dependent; for example, on
    Red Hat Linux it is "/usr/share/locale", but on Solaris it is
    "/usr/lib/locale". The "gettext" module does not try to support
    these system dependent defaults; instead its default is
    "*sys.base_prefix*/share/locale" (see "sys.base_prefix"). For this
    reason, it is always best to call "bindtextdomain()" with an
    explicit absolute path at the start of your application.

[2] 위의 "bindtextdomain()"에 대한 각주를 참조하십시오.
