마이그레이션 절차가 길고 복잡합니다. 그러므로 마이그레이션 단계를 크게 2가지로 나눴습니다.
- 준비 단계: 마이그레이션 전에 필요한 파일을 준비하는 단계
- 마이그레이션 단계: Weblate 컴포넌트를 생성하고 번역 파일을 업로드하는 단계
이번 글은 준비 단계를 중점적으로 설명하겠습니다.
전체적인 흐름
Weblate 마이그레이션은 결국 Zanata에 있는 번역 데이터를 기반으로 Weblate의 구성 요소에 맞게 새로운 번역 프로젝트를 생성하는 것과 같습니다. 일반적인 번역 플랫폼은 번역 템플릿 파일(POT)을 기준으로 번역 파일(PO)을 생성하는 구조를 가지고 있습니다. Weblate 마이그레이션에서도 번역 플랫폼이 사용하는 POT, PO 파일이이 필수적으로 요구됩니다.
준비 단계에서는 크게 3가지 절차로 나뉩니다.
- 작업 환경 구성
- POT 파일 생성
- Zanata에서 PO 파일 추출
자세한 내용은 아래에서 설명하겠습니다.
1. 작업 환경 구성
작업 폴더 구성
마이그레이션은 여러개의 프로젝트를 작업하기 때문에 체계적인 파일 관리가 필요합니다.
그러므로 사전에 작업 폴더를 구성했습니다.
workspace/ # 작업을 위한 루트 디렉토리
├── .venv/ # 독립된 개발환경을 보장하기 위한 파이썬 가상 환경
├── projects/ # 마이그레이션할 프로젝트의 모음
│ └── <project_name>/ # 마이그레이션할 프로젝트
└── requirements/ # 가상환경 설치 시 필요한 의존성의 모음
파이썬 가상 환경 설정
저희 프로젝트의 목표는 zanata에 있는 방식을 그대로 weblate로 이관하는 것입니다. 그러므로 번역 파일을 제어하는 로직 또한 그대로 유지되어야 합니다. 그러므로 openstack-zuul-jobs가 사용하는 가상 환경을 그대로 사용했습니다.
최신 버전의 라이브러리를 사용하게 된다면 django 버전 문제로 인해 연쇄적으로 충돌이 발생하게 됩니다.
우선 설치해야 하는 의존성은 아래와 같습니다.
- openstack-zuul-jobs에서 사용되는 의존성
- horizon 의존성
가상 환경 설치
우선 파이썬의 가상환경을 설치합니다.
작업 환경은 파이썬 버전 3.10입니다.
python3 -m venv $HOME/workspace/.venv
openstack-zuul-jobs에서 사용되는 의존성
바이너리 의존성 관리 도구인 bindep를 사전에 설치합니다. 이후 openstack의 requirements의 폴더를 다운로드 받은 후 upper-constraints.txt 를 설치합니다.
pip3 install bindep
cd requirements
pip3 install -r upper-constraints.txt
horizon 의존성
오픈스택은 다양한 종류의 프로젝트가 있으며, 서로 다른 번역 시스템을 가지고 있습니다.
자세한 내용은 antraxmin님의 OpenStack 프로젝트 유형과 번역 시스템 구조 글을 읽어보시는 것을 추천합니다.
특히 dashboard 유형의 프로젝트의 경우 번역 파일을 추출하기 위해서는 사전에 horizon 의존성을 설치해야 합니다. 그러므로 projects/ 폴더 내에 horizon을 클론하여 내부 의존성을 추가적으로 설치합니다. horizon 또한 마이그레이션 대상이기 때문에 projects 폴더 내에서 프로젝트를 다운로드했습니다.
if [ ! -d "$HOME/workspace/projects/horizon"]; then
mkdir -p $HOME/workspace/projects/horizon
git clone https://opendev.org/openstack/horizon $HOME/workspace/projects/horizon/horizon
fi
cd $HOME/workspace/projects/horizon/horizon
pip3 install -r requirements.txt -r test-requirements.txt &&
pip3 install .
프로젝트 폴더 구조
projects 내에 있는 프로젝트는 아래와 같은 구조를 가집니다.
workspace/
├── .venv/
├── projects/
│ └── <project_name>/
│ ├── <cloned_project>/ # 클론된 원본 프로젝트
│ ├── pot/ # POT 템플릿 파일들
│ └── translations/ # 번역 파일(PO)
└── requirements/
2. POT 파일 준비
가상 환경이 정상적으로 준비되었다면 번역 템플릿 파일과 번역된 파일이 필요합니다.
그 중 번역 템플릿은 번역의 토대를 만드는 파일로 weblate의 컴포넌트를 만들때 필요합니다.
zanata의 경우 pull을 수행하게 되면 번역 템플릿이 아닌 번역된 파일만 얻을 수 있습니다. 그러므로 기존의 프로젝트를 다운로드 받는 후 pybabel 도구로 POT 파일을 생성했습니다.
일관된 결과를 위해 openstack-zuul-jobs에 common_translation_update.sh 로직을 그대로 가져와 사용했습니다.
생성된 pot 파일은 프로젝트 폴더 내에 있는 pot/ 폴더에 저장합니다. pot 파일을 생성한 후 po 파일을 추출하는 과정에서 일부 pot 파일이 삭제되는 문제가 발생했습니다. 이러한 문제를 해결하기 위해 pot 폴더에 일괄적으로 처리하여 추후 쉽게 사용할 수 있도록 구성했습니다.
프로젝트 유형마다 번역하는 방식과 경로가 다릅니다. 그러므로 프로젝트 유형에 맞게 경로를 지정하여 pot 파일을 pot/ 폴더에 복사하는 작업도 추가했습니다.
function preprocess_api_site_pot {
cp $PROJECT_DIR/api-quick-start/locale/api-quick-start.pot "$POT_DIR/api-quick-start.pot"
cp $PROJECT_DIR/firstapp/locale/firstapp.pot "$POT_DIR/firstapp.pot"
}
function preprocess_security_doc_pot {
cp $PROJECT_DIR/security-guide/locale/security-guide.pot "$POT_DIR/security-guide.pot"
}
# ex) doc, doc-install
function preprocess_doc_pot {
local doc_name=$1
cp $PROJECT_DIR/doc/source/locale/$doc_name.pot "$POT_DIR/$doc_name.pot"
}
function preprocess_releasenotes_pot {
cp $PROJECT_DIR/releasenotes/source/locale/releasenotes.pot "$POT_DIR/releasenotes.pot"
}
function preprocess_training_guides_pot {
cp $PROJECT_DIR/doc/upstream-training/source/locale/upstream-training.pot "$POT_DIR/upstream-training.pot"
}
function preprocess_i18n_pot {
cp $PROJECT_DIR/doc/locale/i18n.pot "$POT_DIR/i18n.pot"
}
function preprocess_reactjs_pot {
cp $PROJECT_DIR/i18n/locale/i18n.pot "$POT_DIR/i18n.pot"
}
function preprocess_python_pot {
local modulename=$1
local dest_modulename=$2
cp $PROJECT_DIR/$modulename/locale/$modulename.pot "$POT_DIR/$dest_modulename.pot"
}
function preprocess_django_pot {
local modulename=$1
local target_modulename=$2
local dest_modulename=$3
cp $PROJECT_DIR/$modulename/locale/$target_modulename.pot "$POT_DIR/$dest_modulename.pot"
}
3. Zanata에서 PO 파일 추출
POT 파일을 생성했다면 PO 파일을 가져옵니다.
프로젝트 레포지토리에서는 75%이상 번역된 경우에만 번역 파일을 얻을 수 있습니다. 그러나 번역 플랫폼 마이그레이션이므로 번역 비율에 상관 없이 모든 번역 파일을 가지고 와야합니다.
zanta-cli를 활용하면 zanta에 있는 모든 번역 파일을 쉽게 가져올 수 있습니다.
zanata를 통해 번역을 가져오기 위해서는 아래와 같은 파일이 필요합니다.
- zanta.xml: zanta 설정 정보
- zanata.ini : zanta 자격증명
zanta.ini는 자격 증명으로 zanta 웹사이트에서 로그인하여 쉽게 얻을 수 있습니다.
그러나 zanta.xml의 경우 추가적으로 생성하는 로직이 필요합니다. openstack-zuul-jobs와 동일하게 create-zanata-xml.py 도구를 활용하여 유형별로 zanta.xml를 생성했습니다.
python3 $SCRIPTSDIR/create-zanata-xml.py \
-p $project -v $version --srcdir . --txdir . \
-r '**/*.pot' '{path}/{locale_with_underscore}/LC_MESSAGES/{filename}.po' \
-e "$exclude" -f zanata.xml
zanta는 기본적으로 실행한 디렉토리 위치에 있는 zanta.xml를 읽어서 번역 파일을 가져오게 됩니다. 그러므로zanta.xml를 translations/ 폴더에 복사하여 번역 파일이 폴더 내에 저장될 수 있도록 설정했습니다.
cd $HOME/workspace/projects/$PROJECT/translations
cp $HOME/workspace/projects/$PROJECT/$PROJECT/zanata.xml .
zanata.xml은 zanata의 설정 파일로 프로젝트 이름, locale, PO, POT 파일 위치 등 번역과 관련된 설정 정보가 포함되어 있는 파일입니다. zanta.xml에서 는 rule를 통해 POT,PO의 위치나 파일명을 지정할 수 있습니다.
zun-ui를 예시로 들면 모든 .pot 파일은 {path}/{locale_with_underscore}/LC_MESSAGES/{filename}.po 경로에 저장된다는 의미입니다.
<config xmlns="http://zanata.org/namespace/config/">
<url>https://translate.openstack.org/</url>
<project>zun-ui</project>
<project-version>master</project-version>
<project-type>gettext</project-type>
<src-dir>.</src-dir>
<trans-dir>.</trans-dir>
<rules>
<rule pattern="**/*.pot">{path}/{locale_with_underscore}/LC_MESSAGES/{filename}.po</rule>
</rules>
<excludes>.*/**</excludes>
</config>
아래의 명령어를 실행하면 번역 파일이 rule에 지정한 형태로 다운로드됩니다.
zanata-cli -e -B pull
다운로드하면 아래와 같은 구조로 번역 파일을 다운로드할 수 있습니다.
마무리
지금까지 어떻게 작업 폴더를 구성했으며 POT, PO 파일 생성하는 방식에 대해 설명했습니다. 다음 글에서는 준비한 번역 파일을 가지고 어떻게 Weblate에 맞게 번역 프로젝트를 구성했는지 설명하겠습니다.

