콘텐츠로 이동

추출

추출은 소스 코드에 표시된 모든 메시지를 번역자를 위한 .pot 템플릿으로 모으는 단계로, 튜토리얼 루프의 3단계입니다. 이 페이지는 그 단계의 레퍼런스입니다. 설정, 사용자 정의 함수 이름, strict CI 모드, 그리고 그 후 카탈로그를 지키는 검사를 다룹니다.

추출에는 babel extra가 필요합니다.

python -m pip install "gettext-tstrings[babel]"

작업 흐름

babel.cfg를 만듭니다.

[gettext_tstrings: **.py]
encoding = utf-8

일반 Babel 명령을 그대로 사용합니다.

pybabel extract -F babel.cfg -c "Translators:" -o locales/messages.pot .
pybabel init -i locales/messages.pot -d locales -l ja
pybabel compile -d locales

init은 언어마다 한 번만 실행합니다. 그 뒤로는 pybabel update가 새 템플릿을 기존 카탈로그에 접어 넣습니다. 그 반복되는 주기 — 그리고 그 fuzzy 항목이 릴리스에 무엇을 뜻하는지 — 는 프로덕션에서가 차례로 살펴봅니다.

추출기는 _(), gettext(), ngettext()도 처리합니다. 따라서 한 매핑으로 tr(), ntr(), lazy_gettext(), lazy_pgettext()가 섞인 코드를 모두 다룹니다.

-c로 번역자 주석을 켜기

일반 gettext처럼 번역자 주석을 모으려면 -c "Translators:"를 전달해야 합니다. 빼도 추출은 그대로 동작합니다 — 주석이 카탈로그에 도달하지 않을 뿐이고, 그곳에서 주석은 이 워크플로 전체에서 가장 값싼 품질 지렛대입니다.

사용자 정의 함수 이름

[gettext_tstrings: **.py]
tr_functions = tr translate
ntr_functions = ntr
[[mappings]]
method = "gettext_tstrings"
pattern = "**.py"
tr_functions = ["tr", "translate"]
ntr_functions = ["ntr"]

INI 값은 공백이나 쉼표로 나눈 문자열이고 TOML은 목록을 받습니다. 옵션은 여섯 gettext 함수 계열을 모두 지원합니다.

-k는 t-string에 도달하지 않음

mytr(t"…") 같은 helper는 위 옵션에 선언해야 합니다. Babel의 --keyword는 t-string 리터럴을 읽지 않으므로 pybabel extract -k mytr은 경고 없이 누락합니다.

표준 인수 순서만 지원합니다.

로컬에서는 관대하게, CI에서는 엄격하게

기본적으로 파일 하나가 잘못되어도 실행이 끝나지 않습니다.

  • 거부된 t-string은 경고 후 건너뜁니다.
  • 파싱할 수 없는 파일도 같은 방식으로 격리합니다.
  • tokenize만 거부하는 파일도 격리합니다.

편집하는 동안에는 편리하지만 그렇지 않을 때는 위험합니다. 건너뛴 메시지는 그저 POT에 없을 뿐이라, 번역되지 않으면서 아무것도 그 사실을 알려주지 않습니다. 사람이 추출을 지켜보지 않는 곳에서는 매핑 옵션에 strict = true를 설정하세요.

[gettext_tstrings: **.py]
encoding = utf-8
strict = true
[[mappings]]
method = "gettext_tstrings"
pattern = "**.py"
strict = true

그러면 위의 모든 경고가 하드 실패가 됩니다. 이쪽을 프로덕션 설정으로, 기본값을 로컬 설정으로 여기세요.

기존 도구 체인으로 검증

Babel은 표준 플래그를 추가합니다.

#. gettext-tstrings
#: app.py:4
#, python-brace-format
msgid "Hello {name}"
msgstr ""

こんにちは {nombre} 같은 번역은 추가 설정 없이 감지됩니다.

$ msgfmt --check-format -o /dev/null locales/ja/LC_MESSAGES/messages.po
locales/ja/LC_MESSAGES/messages.po:25: a format specification for argument
'name' doesn't exist in 'msgstr'
msgfmt: found 1 fatal error

Weblate는 이 검사를 Python brace format으로 설명합니다. 각 플랫폼의 동작은 그 플랫폼의 것입니다. 여기서 검증한 도구는 msgfmt와 패키지가 제공하는 Babel checker입니다.

pybabel compile은 표시된 메시지마다 checker를 실행합니다.

$ pybabel compile -d locales -l ja
error: locales/ja/LC_MESSAGES/messages.po:24: translation does not match the
source placeholders: {name} is missing; {nombre} is not in the source message
1 errors encountered.

복수형 오류에는 해당 형태가 표시됩니다.

error: locales/ru/LC_MESSAGES/messages.po:31: msgstr[1]: translation does not
match the source placeholders: {n} is missing

pybabel compile.mo를 계속 기록함

위 오류가 보고되고 종료 상태는 1이지만, 잘못된 카탈로그도 어쨌든 컴파일됩니다. 그 종료 상태만이 파이프라인이 이를 배포하는 것을 막을 수 있으며, 이를 가능하게 하는 빌드 단계는 CI가 막는 것에서 보여줍니다.

두 검사는 중복이 아닙니다. 패키지의 checker는 적어도 두 경우에 더 엄격합니다. 이 checker는 msgfmt가 통과시킬 수 있는 이스케이프된 중괄호와 각 복수형을 따로 검증합니다. ASCII 이름은 모든 도구가 검사하게 하며 라이브러리 자체는 모든 str.isidentifier() 이름을 허용합니다.

템플릿과 다른 도구

t-string은 Python 문법입니다. Jinja2({% trans %}), Django와 다른 템플릿은 자체 추출기를 유지하면서 같은 PO 카탈로그를 사용할 수 있습니다.

pygettext는 아직 t-string을 파싱하지 못합니다. 다른 추출기는 명세의 규약을 구현할 수 있습니다.