Go to the first, previous, next, last section, table of contents.


이진 MO 파일 만들기

msgfmt 프로그램 실행하기

Usage: msgfmt [옵션] 파일이름.po ...
`-a 숫자'
`--alignment=숫자'
문자열을 숫자 바이트 단위로 줄맞춤(align)한다. (기본값: 1).
`-h'
`--help'
도움말을 출력하고 종료한다.
`--no-hash'
바이너리 파일에 해쉬 테이블이 포함되지 않는다.
`-o 파일'
`--output-file=파일'
출력 파일 이름을 file로 지정한다.
`--strict'
msgfmt 프로그램이 엄격하게 유니포럼/썬의 방식을 그대로 따르도록 동작시킨다. 현재 이 옵션은 출력 파일의 이름에만 영향을 줄 뿐이다. 이 옵션이 주어지지 않으면 출력 파일의 이름은 도메인 이름과 같다. 엄격한 유니포럼 모드로 실행될 경우, `.mo' 확장자가 파일 이름에 없을 경우 `.mo'가 뒤에 붙여진다. 우리는 썬의 구현물의 이러한 동작이 너무 바보같다고 생각하므로, 이 모드는 기본적으로 선택되지 않는다.
`-v'
`--verbose'
번역의 오류에서 나올 수 있는 입력 파일의 잘못을 찾아내고 진단한다. msgidmsgstr 문자열을 연구하고 비교한다. msgidmsgstr중 하나가 줄바꿈으로 끝나고, 다른 하나는 그렇지 않다면 정상이 아니라고 취급한다. 또, 만약 문자열이 printf-와 같은 함수에 사용된 형식 문자열일 경우, 두 문자열은 같은 갯수의, 동일한 형의 `%' 형식 지정자가 들어 있어야 한다. 만약 c-codepossible-c-format 플래그가 #, 특별 주석문에 어떤 항목에 나타날 경우, 이 검사가 수행된다. 예를 들어 이 검사는 `%s'에 맞지 않게 `%.*s'를 사용하거나, `%s'에 맞지 않게 `%d'를 사용하거나, `%x'에 맞지 않게 `%d'를 사용하는 경우를 알아낼 수 있다. 이 검사는 인수의 위치 지정까지도 처리한다. 보통 xgettext 프로그램은 자동으로 어떤 문자열이 형식 문자열인지, 아닌지 결정한다. 하지만, 이 알고리즘은 완벽하지 않다. 이 알고리즘은 printf-같은 함수에서 사용되지 않은 문자열의 경우에도 형식 문자열로 취급할 수 있으므로, msgfmt이 이 검사를 수행할 때 오류를 낼 수 있다. 또 한 가지 문제는: 어떤 문자열은 형식 문자열로 취급되지 않을 수도 있으나, printf-같은 함수에서 사용 될 수도 있다. 그러므로, 이 문제를 해결하는 방법은 프로그래머가 xgettext 프로그램에 알려주는 것이다 (see section 키워드 앞에 오는 특수 주석문). 번역자는 #, 플래그를 없앨 생각을 하면 안 된다. #,를 없대는 `교정 작업'을 한다고 해도, 나중에 msgmerge가 실행되자 마자 다시 원상복귀된다.
`-V'
`--version'
버전 정보를 출력하고 종료한다.

만약 입력 파일이 `-'일 경우, 표준 입력에서 읽는다. 만약 출력 파일이 `-'이면, 출력은 표준 출력으로 쓰여진다.

GNU MO 파일 형식

msgfmt으로 만들어 지는 MO 파일의 형식은 아래에 첨가된 그림으로 잘 설명된다.

처음의 두 워드는 파일을 알아보는 데 사용한다. 이 고유 숫자(magic number)는 이 파일이 GNU MO 파일임을 알려준다. 이 숫자는 MO 파일이 만들어지는 기계의 바이트 순서에 따라 기록되므로, 이 고유 숫자는 실제로 두개이다: 그 숫자는 0x950412de0xde120495이다. 두번째로 오는 워드는 이 파일 포맷의 현재 개정판 번호를 뜻한다. 현재 이 개정판 번호는 0이다. 이 번호는 미래에 변경될 수 있고, MO 파일을 읽는 프로그램이 이 파일의 형식이 새로운 형식이라는 걸 알아차리고 제대로 처리할 수 있게 해 준다. 버전에 따라 각각 다른 고유 숫자를 사용하지는 않고, 이렇게 숫자와는 별도로 버전이 저장된다. 그 주요한 이유는 `/etc/magic'은 보통 자주 갱신되지 않기 때문이다. 이러한 정책은 고유 숫자를 내부 형식 판별과는 분리할 수 있다는 점에서 더 좋다.

그 다음에 파일의 뒤쪽에 있는 테이블을 가리키는 포인터들이 있어서 MO 파일을 읽는 프로그램을 다시 컴파일하지 않고 쉽게 MO 파일의 머리부분을 확장할 수 있게 해 준다. 이러한 정책은 나중에 플래그 비트, 사용된 문자셋 판별, 새로운 테이블과 같은 것들을 나중에 첨가할 때 좋을 것이다.

그 다음에 그림에서 OT 오프셋 위치에, 두개의 문자열 디스크립터로 이루어진 테이블이 있다. 두 테이블 내의 각 문자열들은 모두 두개의 32 비트 정수를 사용한다. 한개는 문자열의 길이를 나타내고, 도 하나는 그 문자열의 MO 파일 내에서의 오프셋을 뜻한다. 이 오프셋은 파일의 맨 처음에서부터 바이트 단위로 게산한 것이다. 첫번째 테이블은 원 문자열의 디스크립터가 들어 있고 사전순서대로 오름차 순으로 정렬되어 있다. 두번째 테이블은 번역된 문자열에 대한 디스크립터가 들어 있고, 앞의 테이블과 대응되는 순서로 배열되어 있다: 번역문을 찾으려면 같은 인덱스의 두번째 테이블의 문자열을 가져오면 된다.

원 문자열을 정렬해 놓으면 해쉬 테이블이 없거나 MO 파일에 있는 해쉬 테이블을 쓰지 않는 편이 더 좋을 경우에 간단히 이진 탐색을 사용할 수 있다. 또 한 가지 장점이 있는데, PO 파일의 빈 문자열에 대한 번역은 보통 그 MO 파일에 첨가된 시스템 정보로 번역되어 있기 때문이다. 즉 빈 문자열과 그에 대한 번역문은 자동으로 이 두 테이블의 첫번째에 들어 있게 되고, 시스템 정보를 찾기가 매우 쉽게 된다.

해쉬 테이블의 크기 S는 0일 수도 있다. 이 경우에 해쉬 테이블이 MO 파일에 들어 있지 않은 것이다. 어떤 사람들은 미리 계산된 해쉬 테이블이 디스크 공간을 차지하고, 그렇게 많은 속도 향상은 없기 때문에 해쉬 테이블이 없는 편을 좋아한다. 해쉬 테이블 내에는 MO 파일에서 문자열이 정렬된 테이블상의 인덱스들이 들어간다. 여기에 쓰인 정확한 해싱 알고리즘은 너무 GNU gettext 코드에 관련되어 있으므로, 여기서는 설명되지 않는다.

문자열 자체에 대해서는 해쉬 파일을 따르고, 각각의 문자열은 NUL로 끝난다. 그리고 이 NUL은 문자열 기술자에서 문자열의 길이로 세지 않는다. msgfmt 프로그램은 MO 파일 문자열의 줄맞춤(alignment)을 결정하는 수 있는 옵션이 있다. 이 옵션으로, 각각의 문자열은 줄맞춤 값의 배수가 되는 오프셋에서 시작한다. 몇몇 RISC 기계에서는, 제대로 된 줄맞춤을 통해 속도가 향상될 것이다.

복수형은 원 문자열의 복수형이 원 문자열의 단수형 바로 뒤에 오도록 저장되어 있고, NUL 바이트로 구분된다. 문자열 디스크립터에는 둘 다 들어 있다. 하지만, 오직 원 문자열의 단수형만이 해쉬 테이블에 들어 있다. 번역문의 복수형들은 순서대로 저장되어 있고, NUL 바이트로 구분된다. 마찬가지로 문자열 디스크립터에는 모두 다 들어 있다.

아무 것도 MO 파일의 문자열로 NUL을 포함하는 것을 방해하지 않는다. 하지만, 현재 프로그램의 인터페이스는 문자열이 NUL로 끝난다고 가정하므로, 포함된 NUL은 쓸모없기도 하다. 하지만 MO 파일 포맷을 이렇게 일반적으로 만들면, 나중에 다른 인터페이스를 만들수 있다. 예를 들어 MO 파일 내에 wide 문자를 쓰도록 구현할 수도 있고, 그러면 NUL 바이트는 어디서든지 나타날 수 있다. (아니오, MO 파일에 와이드(wide) 문자가 들어있길 바라지 않는다. 그러면 파일이 불필요하게 커질 것이고, `wchar_t' 타입은 플랫폼에 의존하므로, MO 파일도 플랫폼에 의존하게 될 것이다)

이 문제는 GNU gettext 개발 포럼에서 심각하게 논의되었고, MO 파일 포맷이 시간이 갈수록 발전하고 변화하리라고 예측할 수 있다. 여러 가지 형식이 동시에 지원될 수도 있다고 예상할 수도 있다. 하지만 분명히, 우리는 어디서부턴가 시작해야 하고, 현재의 MO 파일 포맷은 좋은 시작점이다. 구체적으로 확실한 것은 아무것도 없고, 이 포맷은 나중에 아주 쉽게 발전할 수 있으므로, 현재 접근 방법에 대해 너무 걱정할 필요는 없다.

        byte
             +------------------------------------------+
          0  | 고유 숫자 = 0x950412de                   |
             |                                          |
          4  | 파일 형식 revision = 0                   |
             |                                          |
          8  | 문자열의 갯수                            |  == N
             |                                          |
         12  | 원 문자열 테이블의 오프셋                |  == O
             |                                          |
         16  | 번역된 문자열 테이블의 오프셋            |  == T
             |                                          |
         20  | 해쉬 테이블의 크기                       |  == S
             |                                          |
         24  | 해쉬 테이블의 오프셋                     |  == H
             |                                          |
             .                                          .
             .  (나중에 더 많은 항목들이 있을 수있다)   .
             .                                          .
             |                                          |
          O  | 0번째 문자열의 길이 & 오프셋 ---------------.
      O + 8  | 1번째 문자열의 길이 & 오프셋 -----------------.
              ...                                    ...   | |
O + ((N-1)*8)| (N-1)번째 문자열의 길이 & 오프셋         |  | |
             |                                          |  | |
          T  | 0번째 번역문의 길이 & 오프셋 -------------------.
      T + 8  | 1번째 번역문의 길이 & 오프셋 ---------------------.
              ...                                    ...   | | | |
T + ((N-1)*8)| (N-1)번째 번역문의 길이 & 오프셋         |  | | | |
             |                                          |  | | | |
          H  | 해쉬 테이블 시작                         |  | | | |
              ...                                    ...   | | | |
  H + S * 4  | 해쉬 테이블 끝                           |  | | | |
             |                                          |  | | | |
             | NUL로 끝나는 0번째 문자열  <----------------' | | |
             |                                          |    | | |
             | NUL로 끝나는 1번째 문자열  <------------------' | |
             |                                          |      | |
              ...                                    ...       | |
             |                                          |      | |
             | NUL로 끝나는 0번째 번역문  <--------------------' |
             |                                          |        |
             | NUL로 끝나는 1번째 번역문  <----------------------'
             |                                          |
              ...                                    ...
             |                                          |
             +------------------------------------------+


Go to the first, previous, next, last section, table of contents.