AI로 Drupal .po 파일 번역하는 방법

대부분의 사람들은 .po 파일을 WordPress와 연관시키지만, gettext 형식은 WordPress보다 수십 년 앞서 존재했으며 전체 오픈 소스 세계에서 인터페이스 번역을 지원합니다. Drupal은 가장 큰 사용자 중 하나입니다. 다국어 Drupal 사이트를 운영하는 경우, 모든 메뉴 레이블, 필드 설명, 오류 메시지 및 모듈 문자열이 WordPress와 동일한 방식으로 .po 파일을 통해 전달됩니다. 다만, 플레이스홀더 방언과 가져오기 워크플로만 다를 뿐입니다. 그리고 WordPress와 마찬가지로 사이트의 문자열 수가 늘어나면 이러한 파일을 수동으로 번역하는 것이 병목 현상이 됩니다.
이 가이드는 Drupal을 Drupal답게 만드는 요소들을 손상시키지 않고 AI로 Drupal po 파일을 번역하는 방법에 대한 것입니다. Drupal의 번역 시스템, 문자열의 실제 출처, WordPress와 다르며 반드시 보존해야 하는 플레이스홀더 구문, 그리고 반복 가능한 drush 명령을 포함한 전체 내보내기, 번역, 재가져오기 루프를 살펴보겠습니다.
Drupal의 번역 시스템 작동 방식
Drupal은 코어 locale 모듈(현대 Drupal에서는 "인터페이스 번역"이라고도 함)을 통해 인터페이스 번역을 처리합니다. 이 모듈이 활성화되면 각 언어별 원본 문자열과 해당 번역에 대한 데이터베이스 테이블을 관리하며, 이러한 번역을 표준 gettext .po 파일로 가져오고 내보낼 수 있습니다.
관리자 인터페이스는 /admin/config/regional/translate에 있습니다. 여기에서 번역되지 않은 문자열을 검색하고 인라인으로 편집할 수 있으며, 중요하게는 .po 파일을 가져와 번역을 대량으로 로드하거나 현재 상태를 .po 파일로 내보내 오프라인 편집을 할 수 있습니다. 이 내보내기/편집/가져오기 주기가 우리가 최적화하는 워크플로입니다.
각 플러그인과 테마가 languages/ 디렉터리에 자체 .po 및 .mo 파일을 제공하는 WordPress와 달리, Drupal은 인터페이스 문자열을 데이터베이스에 집중화하고 .po를 교환 형식으로 취급합니다. 파일을 내보내고 작업한 다음 다시 가져옵니다. WordPress가 요구하는 컴파일된 .mo 단계는 내부적으로 처리됩니다.
문자열의 출처
Drupal 문자열은 세 가지 출처에서 발생하며, 완전한 번역은 이 모든 것을 포함해야 합니다:
- 코어는 관리자 UI, 양식 및 시스템 메시지에 대한 수천 개의 번역 가능한 문자열을 제공합니다.
- 기여 모듈(Views, Webform, Commerce 등)은 각각
t()함수를 통해 자체 문자열을 등록합니다. - 테마는 템플릿 문자열, 영역 레이블 및 테마 설정 설명을 제공합니다.
/admin/config/regional/translate에서 내보낼 때 번역된 문자열, 번역되지 않은 문자열 또는 모든 문자열로 내보내기 범위를 지정할 수 있습니다. 새로운 번역 작업을 위해 번역되지 않은 문자열만 내보내면 남은 작업만 정확하게 포함된 집중적인 .po 파일이 생성됩니다.
이 세 가지 출처 구조의 실제적 결과: 번역 작업은 결코 진정으로 "완료"되지 않습니다. 기여 모듈을 추가하거나, 새로운 기능을 활성화하거나, Drupal 코어를 업데이트할 때마다 새로운 번역되지 않은 msgid 항목들이 locale 테이블에 나타납니다. 이것이 Drupal 팀이 번역을 일회성 시작 작업이 아닌 반복적인 파이프라인으로 취급하는 이유입니다. 모듈에 영향을 미치는 모든 배포에서 동일한 내보내기, 번역, 재가져오기 루프가 실행되며, 이 루프가 빠를수록 릴리스 간에 번역 부채가 덜 쌓입니다.
Drupal은 localize.drupal.org에서 코어 및 인기 있는 기여 모듈에 대한 커뮤니티 기여 번역을 자동으로 가져올 수 있다는 점도 주목할 가치가 있습니다. 이러한 번역은 일반적인 문자열을 다루지만, 사용자 정의 모듈, 테마 또는 사이트가 실제로 사용하는 프로젝트별 문구를 다루는 경우는 거의 없습니다. 커뮤니티 번역과 완벽하게 현지화된 사이트 사이의 간극은 AI 작업이 빠르게 메우는 부분입니다.
Drupal 플레이스홀더는 WordPress 플레이스홀더와 다릅니다
어떤 Drupal .po 파일을 AI 번역기로 보내기 전에 이해해야 할 가장 중요한 한 가지는 Drupal이 WordPress에서 주로 사용되는 printf 스타일의 %s 및 %1$s 플레이스홀더를 사용하지 않는다는 것입니다. Drupal의 t() 함수는 각각 다른 이스케이프 동작을 가진 세 가지 고유한 플레이스홀더 접두사를 사용합니다:
@variable— 값은 HTML 이스케이프 처리되며, 사용자 제공 텍스트에 대한 안전한 기본값입니다.%variable— 값은 이스케이프 처리되고<em>강조 마크업으로 래핑됩니다.:placeholder— URL 속성에 사용되며 URL sanitization을 통해 실행됩니다.
일반적인 Drupal 원본 문자열은 내보낸 .po 파일에서 다음과 같습니다:
#: core/modules/node/node.module
msgid "@count comments"
msgid_plural "@count comments"
msgstr[0] ""
msgstr[1] ""
#: core/modules/user/user.module
msgid "Welcome @name, you last logged in on %date."
msgstr ""
번역가가 @count를 @cuenta로 변경하거나, @name을 "name"의 번역된 단어로 바꾸거나, 공백을 삽입하여 @count를 @ count로 바꾸면 플레이스홀더가 t() 호출이 전달하는 것과 일치하지 않게 됩니다. 그러면 Drupal은 실제 숫자 대신 리터럴 토큰 @count를 페이지에 인쇄합니다. 번역은 완료된 것처럼 보이지만 사이트는 눈에 띄게 손상됩니다.
이것은 WordPress %s 문자열에 영향을 미치는 버그와 동일한 종류이며, 우리는 이 일반적인 원칙을 코드 변수를 손상시키지 않고 PO 파일을 번역하는 방법에서 심층적으로 다룹니다. Drupal의 특징은 플레이스홀더 스타일이 하나가 아니라 세 가지이며, 번역 도구가 이 모든 것을 인식해야 한다는 것입니다.
일반 번역기가 여기서 실패하는 이유
node.module 문자열을 일반 기계 번역 상자에 붙여넣으면 @count가 손상되거나, <em>로 묶인 %date가 다른 토큰으로 현지화되거나, 복수형이 하나로 축소되는 경우가 자주 발생합니다. 이 도구들은 gettext 의미론을 염두에 두고 만들어진 것이 아닙니다. 그들은 텍스트를 번역할 뿐, @count가 애플리케이션 코드와의 계약이라는 것을 이해하지 못합니다.
**구문 잠금(Syntax Locking)**이 적용된 gettext 인식 번역 파이프라인은 @variable, %variable, :placeholder를 불변 토큰으로 취급합니다. 이들은 번역 전에 잠기고 번역 후에 복원되므로, 주변 문장은 번역되지만 플레이스홀더는 변경되지 않고 통과됩니다. 동일한 잠금은 WordPress %s 및 %1$s, i18next {{name}} 및 인라인 HTML에도 적용됩니다. 이것이 단일 도구가 WordPress 프로젝트만큼 쉽게 Drupal, Symfony 또는 Laravel 프로젝트를 처리할 수 있는 이유입니다. msgid_plural을 통한 Drupal 복수형은 평면화되지 않고 복수형으로 보존되는데, 이는 Drupal 언어가 1개에서 6개까지 복수형 변형을 가질 수 있기 때문에 중요합니다.
더 미묘한 실패 모드도 언급할 가치가 있습니다. Drupal 문자열은 Read the <a href=":url">documentation</a>처럼 번역 가능한 텍스트 안에 인라인 마크업과 링크를 자주 포함합니다. 여기서 :url은 플레이스홀더이고 <a> 태그는 반드시 유지되어야 합니다. 구조를 이해하지 못하는 번역기는 href 속성을 번역하거나, 닫는 태그를 삭제하거나, 플레이스홀더 이름을 현지화할 수 있습니다. 전체 문자열을 단위로 읽는 **맥락 인식 AI(Context-Aware AI)**는 토큰 잠금과 결합되어 마크업과 :url 계약을 모두 손상시키지 않으면서 그 사이에 있는 사람이 읽을 수 있는 "documentation" 텍스트만 번역합니다.
내보내기, 번역, 재가져오기 루프
반복 가능한 워크플로는 세 단계로 구성되며, drush를 사용하면 내보내기 및 가져오기를 스크립트화할 수 있으므로 매번 관리자 UI를 클릭할 필요가 없습니다.
1단계: PO 파일 내보내기
/admin/config/regional/translate에서 언어와 내보내기 범위를 선택하여 UI에서 내보내거나, 명령줄에서 수행할 수 있습니다. locale 모듈은 Drupal의 번역 서비스를 통해 내보내기를 노출하며, 대부분의 팀은 이를 스크립트화합니다. 번역 가져오기를 트리거하는 일반적인 drush 호출(3단계에서 사용하는 역작업)은 다음과 같습니다:
# Re-import a translated PO file for Spanish, overwriting customized strings
drush locale:import es /var/www/translations/es-untranslated.po \
--type=customized --override=all
# Rebuild caches so the new strings render immediately
drush cache:rebuild
내보내기 측면에서는 관리자 내보내기 양식이 .po 파일을 생성합니다. 많은 팀이 완전한 자동화를 위해 locale 내보내기 서비스를 작은 사용자 정의 Drush 명령으로 래핑합니다. 어떤 방법이든 번역되지 않은 msgid 항목을 포함하는 표준 gettext .po 파일로 끝나게 됩니다.
2단계: 파일 번역
이 단계는 AI가 몇 시간의 수동 편집을 대체하는 단계입니다. 내보낸 .po 파일을 클라우드 번역기에 업로드하고, 대상 언어를 선택하고, 처리하도록 합니다. 대규모 사이트의 Drupal .po 파일은 코어, 기여 모듈 및 테마가 결합되면 일상적으로 10MB를 초과하므로, 여기서 **스마트 배치(Smart Batching)**가 중요합니다. 파일은 수동으로 분할하거나 크기 제한에 걸리지 않고 분할, 번역 및 재조립됩니다. 결과물은 모든 msgstr이 채워지고 모든 @count, %date, :url 플레이스홀더가 시작된 위치에 정확하게 있는 완전한 .po 파일입니다.
3단계: Drupal로 재가져오기
번역된 파일을 /admin/config/regional/translate를 통해 다시 가져오거나 위에 표시된 drush locale:import 명령을 통해 가져온 다음 캐시를 재구축합니다. Drupal은 번역을 locale 테이블에 병합하고, 문자열은 사이트 전체에 즉시 나타납니다. 모듈을 추가하거나 코어를 업데이트할 때마다 루프를 다시 실행하십시오. 각 작업은 새로운 번역되지 않은 문자열을 가져오기 때문입니다.
제대로 해야 할 한 가지 가져오기 세부 사항: --override 플래그는 들어오는 번역이 기존 번역을 대체할지 여부를 제어합니다. AI 번역 파일이 권위 있는 것이 되기를 원할 때는 --override=all을 사용하고, 덮어쓰고 싶지 않은 Drupal UI에서 수동으로 조정한 특정 문자열이 있는 경우 더 보수적인 설정을 사용하십시오. 대부분의 자동화된 파이프라인의 경우, .po 파일을 진실의 원천으로 취급하고 모든 것을 덮어쓰는 것이 시스템을 예측 가능하게 유지합니다. 버전 제어의 파일이 사이트에 표시되는 내용입니다. 끝.
여러 대상 언어가 있는 다국어 사이트의 경우, 언어당 한 번 루프가 실행됩니다. 번역되지 않은 세트를 내보내 독일어로 번역하고 가져옵니다. 다시 내보내 스페인어로 번역하고 가져옵니다. 이런 식으로 진행됩니다. 각 언어는 독립적인 .po 파일이므로 병렬로 실행할 수 있으며, 클라우드 번역기가 이를 동시에 처리하면 계약자 시간으로 일주일 걸리던 작업이 오후 한나절로 바뀝니다.
Drupal PO는 여러 형식 중 하나입니다
gettext .po가 Drupal이 번역을 처리하는 유일한 방법이 아니라는 점에 주목할 가치가 있습니다. 구성 및 콘텐츠 엔티티는 XLIFF로도 교환될 수 있습니다. XLIFF는 Translation Management Tool (TMGMT) 모듈이 전문 번역 공급업체 워크플로를 위해 의존하는 표준입니다. Drupal 현지화가 인터페이스 .po 파일 대신 XLIFF를 통해 실행되는 경우, 플레이스홀더 보존 원칙은 동일하지만 파일 구조가 다르며, 이 경로는 Drupal, Symfony, Angular용 XLIFF 파일 번역에서 다룹니다.
하지만 인터페이스 번역 계층에서는 .po가 여전히 핵심입니다. 내보내기, AI 번역, 재가져오기 루프는 며칠 걸리던 수동 작업을 몇 분의 처리 시간으로 단축하며, 사용하는 도구가 gettext 플레이스홀더를 진정으로 이해하는 한 @variable 계약은 손상되지 않고 Drupal 사이트는 출시하는 모든 언어에서 온전하게 유지됩니다.
단 하나의
@variable도 손상시키지 않고 Drupal.po파일을 번역할 준비가 되셨습니까? SimplePoTranslate를 무료로 사용해보세요 — 신용 카드 필요 없습니다. 무료 티어는 전체 구문 잠금(Syntax Locking)이 적용된 표준 gettext.po및.pot파일을 처리하므로, Drupal 플레이스홀더가 코드가 예상하는 대로 정확하게 통과됩니다.