블로그로 돌아가기
A git diff view showing a locale file with three changed keys highlighted, and only those three keys being sent to the translation API below.

모든 것을 다시 번역할 필요는 없습니다: CI에서 델타 번역이 작동하는 방식

By Robert M

모든 내용을 다시 번역할 필요 없음: CI에서 델타 번역 작동 방식

자동 번역을 CI 파이프라인에 연결하면 자연스럽게 다음과 같은 질문이 생깁니다: 누군가 변경 사항을 푸시할 때마다 전체 로케일 파일을 다시 번역하나요?

델타 모드가 없으면 그렇습니다. 소스 로케일 파일에 영향을 주는 모든 푸시는 변경 여부와 상관없이 모든 키, 모든 문자열을 API로 보냅니다. 초기의 작은 프로젝트라면 괜찮지만, 10~20개 언어에 걸쳐 수백 개의 번역 키가 있는 성숙한 프로젝트에서는 마지막 실행 이후 변경되지 않은 문자열에 토큰을 낭비하고 동일한 출력을 받는 셈입니다.

델타 번역은 이를 해결합니다. 전체 파일을 보내는 대신, 액션이 현재 소스 파일과 저장된 기준선(baseline)을 비교하여 추가되거나 수정된 키만 식별해 API에 보냅니다. 변경되지 않은 키의 출력은 기존 번역 파일에서 가져옵니다. 토큰 사용량이 실제 작업량에 맞게 줄어듭니다.


기준선 작동 방식

델타 모드가 처음 실행되거나 전체 새로고침을 강제할 때, 액션은 전체 소스 파일을 번역하고 이를 평탄화한 JSON 표현을 기준선 파일로 리포지토리에 저장합니다. 이후 실행 시 액션은 그 기준선을 불러와 현재 소스 파일과 비교(diff)하여 변경된 키만 포함하는 페이로드를 만듭니다.

JSON 로케일 파일의 경우 기준선은 메시지 디렉터리 내 .polylingo-baseline.json에 저장됩니다. YAML 로케일 파일은 로케일 디렉터리 내 .polylingo-yaml-baseline.json에, Laravel PHP lang 파일은 lang 디렉터리 내 .polylingo-laravel-php-baseline.json에 저장됩니다.

기준선은 번역 파일과 함께 커밋되어 리포지토리와 함께 이동합니다. 리포지토리를 클론하는 모든 개발자는 파이프라인이 사용하는 동일한 기준선을 받습니다.


변경으로 간주되는 것

diff는 소스 파일의 평탄화된 키 표현에 대해 작동합니다. 중첩 구조는 비교 전에 점(.) 표기법 키로 평탄화됩니다:

{
  "nav.home": "홈",
  "nav.about": "회사 소개",
  "hero.title": "우리 플랫폼에 오신 것을 환영합니다",
  "hero.cta": "시작하기"
}

델타 페이로드에 포함되는 키는 다음과 같습니다:

  • 현재 소스 파일에 존재하지만 기준선에는 없는 키(새 키)
  • 둘 다에 존재하지만 값이 변경된 키(수정된 키) 기준선에는 있지만 현재 소스 파일에 없는 키(삭제된 키)는 번역 출력 파일에서 자동으로 제거됩니다. 둘 다에서 동일한 키는 완전히 건너뛰며 기존 번역이 유지됩니다.

실제 사례

Next.js 프로젝트에 messages/en.json에 200개의 번역 키가 있고 이미 12개 언어로 번역되어 있다고 가정합니다. 개발자가 히어로 섹션 문구를 업데이트하고 기능 발표를 위한 두 개의 새 키를 추가했습니다. 200개 중 4개의 키가 변경된 셈입니다.

델타 모드가 없으면 파이프라인은 매 푸시마다 12개 언어에 대해 200개 키 전체를 보냅니다. 델타 모드가 있으면 4개 키만 보냅니다. 해당 실행의 토큰 사용량은 전체 번역 비용의 약 2%입니다. 보낼 데이터가 적고 대기 시간도 짧아 파이프라인도 더 빠릅니다.

한 달간의 정기 개발 동안 절감 효과가 크게 누적됩니다. 대부분의 푸시는 몇 개 문자열만 건드립니다. 전체 재번역은 새 언어를 추가하거나 기준선을 명시적으로 재설정할 때만 발생합니다.


세 가지 PolyLingo GitHub Actions

델타 모드는 세 가지 PolyLingo 번역 Actions 모두에서 사용할 수 있습니다. 각각 특정 콘텐츠 유형과 프로젝트 구조에 맞게 제작되었습니다.

translateAction — JSON 및 Markdown

원본 액션입니다. next-intl 및 i18next 스타일의 평탄한 JSON 로케일 파일을 처리하며, 큰 파일에 대해 비동기 작업 API를 통한 선택적 Markdown 문서 처리도 지원합니다.

- uses: UsePolyLingo/translate-action@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es,ja,zh
    delta: true
    commit: true
    commit_message: "chore(i18n): sync translations"

델타 기준선: messages/.polylingo-baseline.json

github.com/UsePolyLingo/translateAction마켓플레이스에서 보기


translate-action-yaml — YAML 로케일 파일

중첩된 YAML 로케일 파일을 사용하는 프로젝트용: Rails i18n, Vue i18n 및 YAML 형식을 사용하는 기타 프레임워크. 액션은 Rails의 루트 로케일 키 관례를 자동으로 처리합니다 — en.yml에는 en: 루트 키가 있고, 각 출력 파일은 올바른 대상 로케일 키(fr:, de: 등)를 가집니다.

PolyLingo API는 JSON을 기본으로 처리하므로, 액션은 중첩된 YAML을 점(.) 표기법 JSON으로 평탄화하여 전송하고 번역 후 중첩 구조를 재구성하여 유효한 YAML 출력을 작성합니다. v1 주의사항: 점을 포함하는 키는 점 표기법 평탄화와 충돌하므로 지원되지 않습니다.

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    source_file: config/locales/en.yml
    locales: fr,de,es,ja
    delta: true
    commit: true

델타 기준선: config/locales/.polylingo-yaml-baseline.json

github.com/UsePolyLingo/translate-action-yaml마켓플레이스에서 보기


translate-action-laravel — Laravel lang 파일

Laravel 프로젝트용으로, JSON 번역 파일(lang/en.json, Laravel 9+ 스타일의 중첩 및 평탄 구조 모두 지원) 또는 PHP 배열 lang 파일(lang/en/*.php)을 사용합니다. 액션은 php_format: auto로 프로젝트가 사용하는 형식을 자동 감지하며, 먼저 lang/en.json을 확인하고 없으면 PHP 배열 파일로 대체합니다.

PHP 파일의 경우 PHP CLI를 호출해 소스 파일을 읽고, 번역된 출력을 JavaScript 내에서 유효한 PHP 배열 구문으로 직렬화합니다. 추가 의존성은 필요 없습니다. GitHub 호스팅 ubuntu-latest 러너는 기본적으로 PHP 8.x를 포함하므로 별도 설정이 필요 없습니다. PHP 7.4 이상이 필요합니다.

v1 주의사항: 점을 포함하는 키는 점 표기법 평탄화 전략 때문에 PHP 모드에서 지원되지 않습니다.

- uses: UsePolyLingo/translate-action-laravel@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    lang_dir: lang
    source_locale: en
    locales: fr,de,es,pt,nl
    php_format: auto
    delta: true
    open_pr: true

델타 기준선: 형식에 따라 lang/.polylingo-laravel-json-baseline.json 또는 lang/.polylingo-laravel-php-baseline.json

github.com/UsePolyLingo/translate-action-laravel마켓플레이스에서 보기


PR 모드 vs 커밋 모드

세 가지 액션 모두 두 가지 출력 모드를 지원합니다.

커밋 모드 (commit: true)는 번역 파일을 작성하고 현재 브랜치에 직접 커밋합니다. 설정이 간단하며, 번역을 검토가 필요 없는 자동화 프로세스로 취급하는 팀에 적합합니다.

PR 모드 (open_pr: true)는 새 브랜치(polylingo/yaml-<sha>, polylingo/laravel-<sha> 등)를 만들고, 번역 파일을 작성한 후 기본 브랜치에 대해 풀 리퀘스트를 엽니다. 번역 내용 병합 전에 사람의 검토 단계를 원하는 팀이나 번역 품질이 사용자 경험에 직접 영향을 미치는 프로젝트에 적합합니다.

둘 다 설정된 경우 PR 모드가 우선합니다.

PR 모드는 워크플로 권한에 pull-requests: write가 필요합니다:

permissions:
  contents: write
  pull-requests: write

전체 새로고침 강제

델타 모드는 저장된 기준선과 비교합니다. 기준선과 관계없이 모든 것을 다시 번역하려면 delta: false로 설정하세요. 이 설정은 기준선도 현재 소스 파일에 맞게 업데이트하여 이후 델타 실행이 새 상태에서 시작되도록 합니다.

전체 새로고침은 새 대상 언어를 추가할 때, 새 모델 버전에서 번역 품질 개선을 반영하고 싶을 때, 또는 어떤 이유로든 기준선이 실제와 어긋났을 때 유용합니다.

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    locales: fr,de,es,ja,zh,ko,ar
    delta: false  # 전체 새로고침, 기준선 업데이트
    commit: true

하위 단계용 출력

세 가지 액션 모두 동일한 출력을 노출하므로 후속 워크플로 단계에서 사용할 수 있습니다:

- uses: UsePolyLingo/translate-action@v1
  id: translate
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es
    delta: true
    commit: true

- name: 번역 통계 기록
  run: |
    echo "번역된 로케일: ${{ steps.translate.outputs.locales_translated }}"
    echo "변경된 파일 수: ${{ steps.translate.outputs.files_changed }}"
    echo "사용된 토큰 수: ${{ steps.translate.outputs.tokens_used }}"

각 실행은 GitHub Actions 단계 요약에 요약 테이블도 작성하여 로그를 뒤지지 않고도 토큰 사용량과 번역 결과를 확인할 수 있습니다.


시작하기

세 가지 액션 모두 GitHub Marketplace에서 사용할 수 있습니다. PolyLingo API 키가 필요하며, usepolylingo.com에서 무료로 받을 수 있습니다. 무료 플랜은 월 50,000 토큰을 포함합니다. 델타 모드를 활성화하면 대부분의 프로젝트가 일상적인 개발 푸시에서 이 범위 내에 머무릅니다.

API 키를 리포지토리 시크릿(POLYLINGO_API_KEY)으로 추가하고 관련 액션을 워크플로에 추가하세요. 첫 실행은 전체 번역을 수행하고 기준선을 설정합니다. 이후 실행은 변경된 부분만 번역합니다.