Django의 내장 국제화(i18n) 프레임워크를 사용해 본 적이 있다면, 정적 문자열을 잘 처리한다는 것을 알고 계실 것입니다. 텍스트를 gettext()로 감싸거나 {% trans %} 템플릿 태그를 사용하면 문자열이 .po 파일로 추출되고, 번역자가 이를 채웁니다. 이 시스템은 오랫동안 검증되었으며 코드와 템플릿에서 훌륭하게 작동합니다.
하지만 데이터베이스에 저장된 콘텐츠는 어떨까요?
상품명, 기사 제목, 카테고리 설명, FAQ 답변, 사용자 생성 콘텐츠. 이 중 어느 것도 소스 코드에 존재하지 않습니다. Django의 makemessages 명령으로는 절대 찾을 수 없으며, .po 파일로는 해결할 수 없습니다. 애플리케이션이 여러 언어로 동적 콘텐츠를 사용자에게 제공해야 한다면, 다른 전략이 필요합니다.
방법은 다음과 같습니다: django-modeltranslation을 사용하여 모델에 번역 가능한 필드를 추가한 다음, TranslateBot을 사용하여 AI로 번역을 자동화합니다.
Django 데이터베이스 번역 패키지
여러 서드파티 패키지가 데이터베이스 번역 문제를 해결하며, 각각 다른 아키텍처를 가지고 있습니다.
django-modeltranslation
기존 테이블에 언어별 컬럼을 직접 추가합니다. title 필드는 title_en, title_de, title_fr 등이 됩니다. 모든 것이 같은 테이블에 있으므로 쿼리가 빠릅니다. 관리자 인터페이스에서 모든 언어를 나란히 보여줍니다.
- 장점: JOIN 없음, 빠른 쿼리, 필드 디스크립터를 통한 투명한 접근, 성숙한 생태계
- 단점: 새 언어마다 스키마 변경, 넓어지는 테이블
django-parler
각 모델에 대해 별도의 번역 테이블을 생성합니다. 원본 테이블은 깔끔하게 유지되고, 번역은 외래 키로 연결된 관련 테이블에 저장됩니다.
- 장점: 깔끔한 스키마, 마이그레이션 없이 쉽게 언어 추가
- 단점: 번역된 콘텐츠에 JOIN 필요, 다소 복잡한 쿼리 패턴
django-translations
단일 번역 테이블에 제네릭 외래 키를 사용하여 모든 모델을 가리킵니다. 모든 모델의 모든 번역이 하나의 테이블에 들어갑니다.
- 장점: 최소한의 스키마 변경, 모든 모델에서 작동
- 단점: 제네릭 외래 키 쿼리가 느릴 수 있음, 덜 투명한 API
수동 JSON 필드
JSONField에 번역을 저장할 수 있습니다:
class Product(models.Model):
name_translations = models.JSONField(default=dict)
# {"en": "Running Shoes", "de": "Laufschuhe", "fr": "Chaussures de course"}
- 장점: 추가 의존성 없음, 유연함
- 단점: ORM 통합 없음, 관리자 지원 없음, 모든 것을 수동으로 처리
어떤 것을 사용해야 할까요?
대부분의 프로젝트에서 django-modeltranslation이 최선의 선택입니다. 가장 성숙한 패키지이며, Django 관리자 통합이 가장 뛰어나고, 빠른 쿼리를 위해 모든 데이터를 같은 테이블에 유지합니다. 단점(넓어지는 테이블과 새 언어마다 마이그레이션)은 대다수 애플리케이션에서 감당할 수 있습니다. 이 가이드의 나머지 부분에서는 django-modeltranslation을 사용합니다.
django-modeltranslation 단계별 설정
1단계: 패키지 설치
TranslateBot은 django-modeltranslation을 선택적 의존성으로 포함합니다. 한 번에 둘 다 설치하세요:
pip install translatebot-django[modeltranslation]
또는 uv를 사용하는 경우:
uv add --dev translatebot-django[modeltranslation]
2단계: Django 설정 구성
settings.py에서 중요한 두 가지: 앱 순서와 언어 목록입니다.
# settings.py
INSTALLED_APPS = [
'modeltranslation', # Must be BEFORE django.contrib.admin
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Your apps
'shop',
'translatebot_django',
]
LANGUAGE_CODE = 'en'
LANGUAGES = [
('en', 'English'),
('de', 'German'),
('fr', 'French'),
('nl', 'Dutch'),
]
modeltranslation 앱은 django.contrib.admin보다 앞에 와야 합니다. 그래야 번역 필드를 보여주도록 관리자 클래스를 패치할 수 있습니다.
3단계: 번역할 모델 등록
번역 가능한 모델이 있는 각 앱에 translation.py 파일을 생성합니다. 전자상거래 쇼핑 앱의 경우:
# shop/translation.py
from modeltranslation.translator import register, TranslationOptions
from .models import Product, Category
@register(Product)
class ProductTranslationOptions(TranslationOptions):
fields = ('name', 'description', 'short_description')
@register(Category)
class CategoryTranslationOptions(TranslationOptions):
fields = ('name', 'description')
사람이 읽을 수 있는 텍스트가 포함된 필드만 포함하세요. slug, price, sku 같은 필드는 등록하지 마세요.
4단계: 마이그레이션 생성 및 실행
python manage.py makemigrations
python manage.py migrate
이후 shop_product 테이블에 새 컬럼이 생깁니다:
| Column | Type |
|---|---|
name |
varchar(200) |
name_en |
varchar(200) |
name_de |
varchar(200) |
name_fr |
varchar(200) |
name_nl |
varchar(200) |
description |
text |
description_en |
text |
description_de |
text |
description_fr |
text |
description_nl |
text |
short_description |
text |
short_description_en |
text |
short_description_de |
text |
short_description_fr |
text |
short_description_nl |
text |
LANGUAGES에 정의한 각 언어마다 등록된 각 필드에 대해 자체 컬럼이 생성됩니다.
문제: 비어 있는 번역 필드
이제 스키마는 갖추었지만, 모든 _de, _fr, _nl 컬럼이 비어 있습니다. 500개의 상품에 3개의 번역 가능한 필드와 3개의 대상 언어가 있다면, 4,500개의 빈 필드가 채워지기를 기다리고 있는 것입니다.
해당 콘텐츠를 수동으로 번역하는 것은 현실적이지 않습니다. 전문 번역 서비스를 이용하더라도 데이터를 내보내고, 보내고, 납품을 기다리고, 결과를 다시 가져와야 합니다. 소규모 팀이나 1인 개발자에게 이는 보통 기능이 출시되지 않는다는 것을 의미합니다.
여기서 TranslateBot이 등장합니다.
TranslateBot으로 번역 자동화
TranslateBot의 translate 관리 명령은 AI를 사용하여 빈 필드를 모두 채울 수 있습니다. 먼저 API 키를 설정하세요:
# settings.py
TRANSLATEBOT_API_KEY = os.getenv("OPENAI_API_KEY")
TRANSLATEBOT_MODEL = "gpt-4o-mini" # Fast and cost-effective
그런 다음 등록된 모든 모델을 대상 언어로 번역합니다:
python manage.py translate --target-lang de --models
이 단일 명령은 django-modeltranslation에 등록된 모든 모델을 찾고, 대상 언어에서 비어 있는 필드를 식별하며, AI 생성 번역으로 채웁니다.
특정 모델 번역
상품만 번역하고 카테고리는 번역하지 않으려면:
python manage.py translate --target-lang de --models Product
또는 여러 특정 모델:
python manage.py translate --target-lang de --models Product Category
드라이 런으로 미리보기
데이터베이스에 쓰기 전에 항상 미리 확인하세요:
python manage.py translate --target-lang de --models --dry-run
이렇게 하면 레코드를 수정하지 않고 정확히 무엇이 번역될지 보여줍니다.
기존 콘텐츠 재번역
기본적으로 TranslateBot은 이미 번역이 있는 필드를 건너뜁니다. 기존 번역을 덮어쓰려면(예: AI 모델을 개선하거나 컨텍스트를 추가한 후):
python manage.py translate --target-lang de --models --overwrite
모든 언어를 한 번에 번역
--target-lang을 생략하고 설정에 LANGUAGES가 정의되어 있으면, TranslateBot이 구성된 모든 언어로 번역합니다:
python manage.py translate --models
번역 파이프라인 작동 방식
translate 명령을 실행하면 다음과 같은 일이 일어납니다.
-
탐색. TranslateBot은 django-modeltranslation의 레지스트리를 쿼리하여 등록된 모든 모델과 번역 가능한 필드를 찾습니다.
-
소스 감지. 각 레코드에 대해 소스 콘텐츠를 읽습니다. 먼저 기본 필드(예:
name)를 확인한 다음, 첫 번째로 채워진 언어별 필드(예:name_en)로 폴백합니다. 소스 콘텐츠가 없는 레코드는 건너뜁니다. -
배치 처리. 레코드를 배치로 그룹화하여 AI 제공업체에 보냅니다. 이렇게 하면 API 호출이 효율적이고 속도 제한에 걸리지 않습니다.
-
번역. 각 배치는 구성된 AI 모델을 사용하여 번역됩니다. LiteLLM이 지원하는 모든 LLM 제공업체(OpenAI, Anthropic, Google, Azure 등) 또는 DeepL을 사용할 수 있습니다.
-
원자적 쓰기. 번역 실행의 모든 데이터베이스 업데이트는 단일 트랜잭션으로 래핑됩니다. API 오류나 데이터베이스 제약 조건 위반 등 문제가 발생하면 부분 데이터가 저장되지 않습니다. 전부 아니면 전무입니다.
전체 워크플로우 예제
모델 정의부터 번역된 콘텐츠까지의 전체 예제로, 전자상거래 Product 모델을 사용합니다.
모델 정의
# shop/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
short_description = models.CharField(max_length=500, blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
sku = models.CharField(max_length=50, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
번역 등록
# shop/translation.py
from modeltranslation.translator import register, TranslationOptions
from .models import Product
@register(Product)
class ProductTranslationOptions(TranslationOptions):
fields = ('name', 'description', 'short_description')
마이그레이션 실행
python manage.py makemigrations shop
python manage.py migrate
번역 컨텍스트 추가 (선택 사항)
프로젝트 루트에 TRANSLATING.md 파일을 만들어 AI에 제품 도메인에 대한 컨텍스트를 제공합니다:
# Translation Context
## About This Project
E-commerce store for outdoor sports equipment.
## Terminology
- "trail runners" refers to trail running shoes, not people
- Keep brand names (Nike, Salomon, Arc'teryx) untranslated
- "Gore-Tex" is a brand name, do not translate
## Tone
- Use informal "du" form in German
- Product descriptions should sound enthusiastic but not exaggerated
번역
# Preview first
python manage.py translate --target-lang de --models Product --dry-run
# Apply translations
python manage.py translate --target-lang de --models Product
출력:
Translating Product model fields to German (de)...
Found 142 products with untranslated fields
Translating batch 1/15...
Translating batch 2/15...
...
Translating batch 15/15...
Successfully translated 142 products
관리자에서 확인
Django 관리자를 열고 아무 상품이나 선택하면 번역 필드가 채워져 있는 것을 볼 수 있습니다:
- Name [de]: Ultraleichte Trail-Laufschuhe
- Description [de]: Diese leichten Trail-Laufschuhe bieten hervorragenden Grip...
- Short description [de]: Leicht, schnell und griffig auf jedem Untergrund.
각 대상 언어에 대해 반복합니다:
python manage.py translate --target-lang fr --models Product
python manage.py translate --target-lang nl --models Product
또는 모든 언어를 한 번에 번역합니다:
python manage.py translate --models Product
모범 사례
프로덕션에서 대량 번역을 실행하기 전에 데이터베이스를 백업하세요. TranslateBot은 원자적 트랜잭션을 사용하므로 실패한 실행은 부분 데이터를 남기지 않습니다. 하지만 번역 품질이 기대에 미치지 못할 경우 되돌릴 수 있도록 백업을 해두는 것이 좋습니다.
# PostgreSQL example
pg_dump mydb > backup_before_translation.sql
먼저 드라이 런을 사용하세요. 새 모델이나 언어에 번역을 적용하기 전에 항상 --dry-run으로 실행하세요. 소스 콘텐츠가 올바르게 감지되고 번역이 합리적으로 보이는지 출력을 검토하세요.
대규모 데이터베이스에서는 한 번에 하나의 모델씩 번역하세요. 이렇게 하면 결과를 검토하고 필요시 특정 모델을 다시 실행하기가 쉬워집니다.
python manage.py translate --target-lang de --models Product
python manage.py translate --target-lang de --models Category
python manage.py translate --target-lang de --models Article
번역 컨텍스트를 추가하세요. 도메인별 용어와 톤 가이드라인이 포함된 TRANSLATING.md 파일은 번역 품질을 크게 향상시킵니다. 이는 의학, 법률, 기술 제품 같은 전문 분야에서 특히 중요합니다.
소스 언어를 항상 채워두세요. TranslateBot은 기본 필드 또는 소스 언어 필드에서 읽습니다. 데이터 입력 워크플로우가 항상 소스 언어를 채우도록 하세요. 소스 필드가 비어 있으면 번역도 비어 있게 됩니다.
전체 범위를 위해 PO 파일 번역과 결합하세요. 코드 문자열과 데이터베이스 콘텐츠를 모두 번역합니다:
# Static strings in code and templates
python manage.py makemessages -l de -l fr -l nl
python manage.py translate
python manage.py compilemessages
# Dynamic content in the database
python manage.py translate --models
이렇게 하면 사용자가 보는 모든 문자열이, 템플릿에서 오든 데이터베이스에서 오든, 번역됩니다.
다음 단계
- 사용 가능한 모든 옵션에 대한 전체 명령 레퍼런스를 읽으세요
- CI 통합을 설정하여 누락된 번역을 자동으로 확인하세요
- 지원되는 AI 모델을 탐색하여 프로젝트에 가장 적합한 품질과 비용의 균형을 찾으세요