다국어 지원을 할 때, gettext를 많이 써먹게 됩니다. 이 글에서는 mo와 po 파일에 대해서 간단하게 알아봅니다. gettext가 설치하시고 진행해 주세요. 이 글에서는 xgettext, msgmerge, msgfmt 명령어의 상세한 것을 다루지 않습니다. 이 글에서는, 다국어 지원하기 위해 어떻게 해야 하는지에 대한 process를 다루게 됩니다.
gettext mo po 파일
먼저, mo와 po 파일에 대해서 그림으로 간단하게 알아보도록 합시다.
먼저, xgettext로 source로부터, gettext string을 모두 추출합니다. 이들이 번역 재료가 됩니다. 어? 무슨 이야기인가?
- Hello
- My name is cho
라는 것을 번역하고 싶어요. 그러면, py 파일이던, c++ 파일 안에 gettext 처리를 하겠지요? 이들이 번역 재료가 되는 것입니다. 다음, msgmerge가 있어요. 이건 무엇을 하는 건가? merge. 합치는 것입니다. merge sort는 합치는 방식으로 sort를 하는 것이고요. merge branch는 두 브랜치의 변경 사항을 병합하는 것입니다.
마찬가지입니다. 여러 .po나 .pot 파일에 있는 내용들을 병합할 때 msgmerge 명령어를 쓰게 됩니다.
그러면, 두 파일들을 merge 해서 새로운 결과를 만들어 낼 수 있습니다. 이것이 msgmerge의 역할입니다. 그런데, c++이나, c 소스 파일만 있다고 실행되지는 않아요. 컴파일 해서 obj를 만들고, 실행 파일을 만들어야 합니다. 마찬가지. 이 po 파일을 컴파일 해서 mo 파일로 만드는 것이, msgfmt입니다.
이 mo 파일을 python 프로그램이나, 다른 파일이 불러오면, 번역이 되는 것입니다. 여기까지 po와 mo 파일이 어떤 식으로 다국어에서 동작하는지 이해가 가시나요?
- po는 소스 파일. 그러니까 msg를 어떻게 번역할 것인지 정보를 저장합니다.
- mo는 po를 컴파일한 파일. 프로그램이 mo를 바탕으로 해석해요.
여기까지 따라 오셨다면, 실습을 하나 해 보겠습니다.
번역해 보기
자. 그러면, 실습 하나 해 보겠습니다.
프로젝트 구조는 위와 같아요. locale/ko/LC_MESSAGES 밑에 po와 mo 파일이 들어갈 거에요. 그리고, locale 밑에 base.po가 하나 들어갈 겁니다. 이는, base.po는 gettext로 추출한 문구만 남기기 위함입니다.
locale/{lang}/LC_MESSAGES가 중요해요. gettext가 인식하는 폴더 구조이니, 잘 익혀두세요.
먼저, main.py 입니다. 1번째 인자는 body.po를 읽겠다는 것을 의미합니다. 2번째는 locale 밑에 있는 폴더에 language 번역 정보가 들어있다는 것을 의미해요. 다음 _를 t.gettext로 하였는데, 이렇게 하면 _를 호출했을 때, 문자열을 제가 특정한 언어로 번역하게 됩니다. 더 정확히 말하면
- gettext의 추출 대상이 됩니다.
- mo가 있다면, 이를 기반으로 해석하게 됩니다.
자. 이제, xgettext 명령어를 사용할 건데요. locale 밑에 base.po라는 이름으로 현재 디렉토리에 있는 모든 py 파일에 대해 source로부터 gettext를 추출한 결과를 생성할 거에요.
그러면, 요런 내용이 들어가 있음을 볼 수 있어요. 여기서, 아무것도 건드리지 말고, Content-type 부분에서 charset만 UTF-8로 바꾸어 줍시다. 저는 이 base.po를 그대로 쓰지 않습니다. locale 밑에 각각의 언어 폴더가 있고, 그 밑에 LC_MESSAGES 라는 폴더를 만들어서 관리할 것이기 때문이에요.
자. locale/base.po의 내용을 그대로 locale/ko/LC_MESSAGES 밑에 있는 body.po에 복사합시다. 그러면, 이제 프로젝트 구조가 위 그림과 같이 됩니다. 여기까지 한 것이 뭔가?
- 소스로부터 gettext string을 추출한 결과를 base.po에 저장해 놓았습니다.
- 각 언어별로 body.po를 저장해 놓았습니다.
여기까지 정리 되시나요? 이제, locale/ko/LC_MESSAGES에 들어가서, body.po를 보도록 하겠습니다.
그러면, msgstr에 아무것도 없을 겁니다. 그냥 “”만 있겠지요. msgid는 키 값, 그리고 msgstr은 키 값에 대해 어떻게 번역할 것인지를 의미합니다. “hello”는 “안녕하세요”로 번역되면 되고, 문장 “new game is started”는 “새로운 게임이 시작되다” 정도로 번역하면 됩니다. 그러니 위와 같이 작성해 주겠습니다.
그 다음에 어떻게 해야 겠나요? 소스 파일은 있는데 컴파일 결과가 없네요.
그러면 컴파일을 해야 겠지요? msgfmt로 컴파일 합시다. 그러면, body.po 파일에 대해, 컴파일 결과인 body.mo가 나오게 됩니다.
실행 결과는 위와 같습니다. 저는 ko 언어로 번역했기 때문에, 안녕하세요와, 새로운 게임이 시작되다로 번역되었습니다.
번역할 구문 추가하기
그런데, 번역 구문이 추가되면 어떻게 해야 할까요? gettext mo po 파일 둘 다 업데이트 되어야 겠지요. 그러면, 업데이트 되어야 할 것이 3군데입니다.
- base.po
- 각 언어별로 body.po
- 각 언어별로 컴파일 결과인 body.mo
하나씩 진행해 볼게요.
hey!가 번역되어야 할 것에 추가되었습니다.
base.po는 새로 생성합니다. base.po는 번역본이 지워져도 되기 때문에 새로 생성해도 무난합니다. 그런데 중요한 것은, msgmerge를 사용해서, 각 언어별로 body.po를 locale/base.po를 참조해서 업데이트 했다는 점입니다.
이제, locale/ko/LC_MESSAGES/body.po와 locale/base.po를 보겠습니다.
먼저 base.po는 msgid만 들어가 있습니다. msgstr에는 아무 것도 없다는 것을 주목해 보세요.
body.po에는 “hey!” 라는 내용만 추가되었습니다. msgstr에 제가 번역할 내용을 적어줍니다.
내용이 바뀌었다면, mo 파일에 반영하기 위해 다시 컴파일을 합니다.
이제, main.py를 실행해 봅시다. 그러면, hey!가 어이!로 번역되었다는 것을 볼 수 있습니다.