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
任意のモデルを指すジェネリック外部キーを持つ単一の翻訳テーブルを使用します。すべてのモデルのすべての翻訳が1つのテーブルに格納されます。
- メリット: スキーマ変更が最小限、任意のモデルで動作
- デメリット: ジェネリック外部キーのクエリが遅くなる場合がある、透明性の低い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で重要なのは2つ:アプリの順序と言語リストです。
# 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ファイルを作成します。ECサイトのショップアプリの場合:
# 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テーブルに新しいカラムが追加されます:
| カラム | 型 |
|---|---|
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カラムが空です。3つの翻訳可能なフィールドと3つの対象言語を持つ500個の商品がある場合、埋める必要のある4,500個の空のフィールドがあります。
このコンテンツを手動で翻訳するのは現実的ではありません。プロの翻訳サービスを使っても、データをエクスポートし、送信し、納品を待ち、結果をインポートし直す必要があります。小さなチームやソロ開発者にとって、これは通常その機能が永遠にリリースされないことを意味します。
ここで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
この1つのコマンドで、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
翻訳パイプラインの仕組み
翻訳コマンドを実行すると、以下のことが起こります。
-
検出。 TranslateBotはdjango-modeltranslationのレジストリをクエリして、登録されたすべてのモデルとその翻訳可能なフィールドを見つけます。
-
ソース検出。 各レコードについて、ソースコンテンツを読み取ります。まずベースフィールド(例:
name)をチェックし、次に最初に値が入っている言語固有フィールド(例:name_en)にフォールバックします。ソースコンテンツのないレコードはスキップされます。 -
バッチ処理。 レコードはバッチにグループ化され、AIプロバイダーに送信されます。これによりAPI呼び出しが効率的になり、レート制限への到達を回避します。
-
翻訳。 各バッチは設定されたAIモデルを使用して翻訳されます。LiteLLMがサポートする任意のLLMプロバイダー(OpenAI、Anthropic、Google、Azureなど多数)やDeepLを使用できます。
-
アトミック書き込み。 1回の翻訳実行のすべてのデータベース更新は、単一のトランザクションにラップされます。APIエラーやデータベース制約違反など、何か問題が発生した場合、部分的なデータは保存されません。全部か無しかです。
完全なワークフロー例
モデル定義から翻訳済みコンテンツまでの完全な例を、ECサイトの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で実行してください。ソースコンテンツが正しく検出され、翻訳が妥当に見えることを確認するために出力を確認してください。
大規模なデータベースでは一度に1つのモデルを翻訳してください。これにより結果の確認が容易になり、必要に応じて特定のモデルを再実行できます。
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モデルを探索する