Back to blog

Django Translation for Solo Developers: From Weeks to Minutes

2026-02-11 8 min read
Django Translation for Solo Developers: From Weeks to Minutes

You built a Django app. It works, users are signing up, and now you want to reach people who don't speak English. The problem is obvious the moment you look at it: Django's internationalization framework is excellent at extracting translatable strings, but it does absolutely nothing to fill in the translations. That part is on you.

If you're a solo developer or a two-person team, the gap between makemessages and a fully translated app can feel enormous. I'll walk through the realistic options, explain why most of them fall apart for small teams, and show a workflow that takes translation from a multi-week chore to a two-minute command.

The Traditional Options (and Why They Hurt)

Option 1: Copy-Paste from Google Translate

The most common first attempt. You open your .po file, copy each msgid into Google Translate, paste the result back as msgstr, and repeat. For every string. In every language.

A typical Django app has 200-500 translatable strings. If you're translating to five languages, that's 1,000-2,500 copy-paste cycles. Even if each one takes only 30 seconds, you're looking at 8-20 hours of mind-numbing work. And that's before you fix the formatting errors, broken placeholders, and inconsistent terminology that inevitably creep in.

Worse, you have to do it again next sprint when you add new strings.

Option 2: Professional Translators

Professional translation typically costs $0.10 to $0.25 per word. A Django app with 500 strings averaging 8 words each works out to roughly 4,000 words. At $0.15/word, that's $600 per language, or $3,000 for five languages.

For a VC-funded startup, that's a rounding error. For a solo developer charging $9/month per user, it can eat your entire revenue for the quarter.

Option 3: Fiverr and Freelance Marketplaces

You can find translators on Fiverr for $20-50 per language. Some are genuinely skilled. Many are simply pasting your text into Google Translate and charging you for the privilege. You end up with the same quality as Option 1, plus an extra round-trip of communication and a week of waiting.

Option 4: Crowdin, Transifex, or Weblate

These platforms are powerful, but they're designed for projects with dedicated translation teams. The setup overhead (syncing repositories, configuring translation memory, managing contributor access) is overkill when you're the only person on the project. Monthly subscriptions start at $30-150/month for paid tiers, and even free tiers require you to maintain yet another third-party integration.

Option 5: Paste Everything into ChatGPT

This actually works surprisingly well for quality. You paste your .po file contents into ChatGPT or Claude, ask for translations, and get reasonable results. The problem is that it doesn't scale. You have to manually extract the untranslated strings, format the prompt, parse the response back into .po format, and handle batching when you exceed context limits. It works once. It breaks down as a repeatable workflow.

The Automation Approach

What if the entire translation step was a single command? That's the idea behind TranslateBot, an open-source Django management command that reads your .po files, sends untranslated strings to an AI provider, and writes the translations back in the correct format.

Here's how to set it up.

Step 1: Install TranslateBot

uv add --dev translatebot-django

Or with pip:

pip install translatebot-django

Add it to your installed apps:

# settings.py
INSTALLED_APPS = [
    # ...
    'translatebot_django',
]

Step 2: Configure Your AI Provider

Add two settings:

# settings.py
import os

TRANSLATEBOT_API_KEY = os.getenv("OPENAI_API_KEY")
TRANSLATEBOT_MODEL = "gpt-4o-mini"

TranslateBot works with OpenAI, Anthropic Claude, Google Gemini, and 100+ other models through LiteLLM. It also supports DeepL as a dedicated translation backend.

A TRANSLATING.md file in your project root gives the AI context about your application. This is what separates generic machine translation from translations that actually fit your product:

# Translation Context

## About This Project
A personal finance tracker for freelancers. Users track invoices,
expenses, and tax obligations.

## Tone
- Friendly and informal
- Use "du" in German, "tu" in French
- Keep financial terms precise

## Terminology
- "invoice" = "Rechnung" (German), "facture" (French)
- "dashboard" = keep as English loanword in all languages
- "freelancer" = keep as English loanword in German

This file is sent along with every translation request, so the AI consistently uses the right tone and terminology.

Step 4: Translate

python manage.py makemessages -l de -l fr -l nl -l es -l ja
python manage.py translate
python manage.py compilemessages

Three commands. That's it. TranslateBot finds all untranslated strings across all your .po files, translates them in batches, and writes the results back. Only empty entries are translated by default, so running the command again after adding new strings only translates the new ones.

What This Looks Like in Practice

Here's a realistic sprint workflow for a solo developer supporting five languages:

Monday: You build a new feature. You add a few new translatable strings using gettext() and {% trans %} as you go.

from django.utils.translation import gettext_lazy as _

class InvoiceView(View):
    def post(self, request):
        # New string added during development
        messages.success(request, _("Invoice sent successfully."))

Before committing: You run three commands:

python manage.py makemessages -a --no-obsolete
python manage.py translate
python manage.py compilemessages

The translate command detects the new untranslated entries and translates only those. If you added 5 new strings and you support 5 languages, it makes 25 translations in a single API call. The whole process takes under a minute.

You commit your code, templates, and updated .po/.mo files together. Translations are part of your normal development flow, not a separate project.

Preview Before You Commit

If you want to see translations before they're written to disk, use dry-run mode:

python manage.py translate --dry-run

This prints every translation to the terminal without modifying any files.

The Cost Comparison

Here's where automation becomes hard to argue against.

Approach 500 strings, 5 languages Time Recurring cost
Manual copy-paste Free ~40 hours ~8 hrs/sprint
Professional translators ~$3,000 1-2 weeks ~$600/sprint
Fiverr translators ~$100-250 3-7 days ~$50/sprint
Crowdin/Transifex $30-150/mo Setup: hours Ongoing
TranslateBot + GPT-4o-mini ~$0.05 ~2 minutes ~$0.01/sprint
TranslateBot + DeepL Free $0 ~2 minutes $0

A small-to-medium Django app with around 500 translatable strings typically costs under $0.01 per language with gpt-4o-mini. For most solo projects, the DeepL free tier (500,000 characters/month) covers everything at zero cost.

To be clear: AI translations aren't perfect. Neither are budget human translations. The difference is that AI translations cost almost nothing, arrive instantly, and can be re-run whenever you want.

CI Integration: Never Ship Untranslated Strings

One of the most useful patterns I've found as a solo developer is adding a translation check to CI. TranslateBot includes a check_translations command that fails if any .po file has untranslated or fuzzy entries:

# .github/workflows/ci.yml
jobs:
  translations:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - run: uv python install
      - run: uv sync --frozen
      - name: Install gettext
        run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext
      - name: Check translations
        run: uv run python manage.py check_translations --makemessages

If you add a new {% trans %} tag in a template and forget to run translate, CI will catch it:

locale/de/LC_MESSAGES/django.po: 1 untranslated, 0 fuzzy
locale/fr/LC_MESSAGES/django.po: 1 untranslated, 0 fuzzy
CommandError: Translation check failed

This turns translations from something you remember to do into something you can't forget.

Practical Tips

Start with two or three languages. You don't need to launch in 15 languages on day one. Pick the ones where you have the most users or the largest addressable market. German, French, and Spanish cover a lot of ground for European markets.

Have native speakers review critical strings. AI translations are good enough for most UI text, but your landing page headline and onboarding flow deserve a human eye. Ask a friend, a user, or someone in a community forum to spend 10 minutes reviewing the most visible strings.

Use dry-run before overwriting. If you ever need to re-translate everything (for example, after updating your TRANSLATING.md with better terminology guidelines), preview the changes first:

python manage.py translate --overwrite --dry-run

Keep TRANSLATING.md in version control. It's part of your project's translation configuration. When you update terminology or tone guidelines, the next translate run will reflect those changes for any new strings.

Translate per app when needed. If you only changed strings in one app, you can scope the translation:

python manage.py translate --app billing

From Weeks to Minutes

Django's internationalization framework is one of the best in any web framework. The tooling for makemessages, locale directories, and compilemessages is mature and reliable. The only piece that was missing was the translation step itself. That used to be the expensive, slow part.

With TranslateBot, the workflow becomes:

  1. Write code with gettext() and {% trans %} as normal
  2. Run makemessages to extract strings
  3. Run translate to fill in translations
  4. Run compilemessages to compile
  5. Commit everything together

For a solo developer, this means localization is no longer a project you plan for "someday." It's something you can do today, in the time it takes to make a cup of coffee.

TranslateBot is open source and available on PyPI and GitHub. Install it, run the command, and see your app in a new language in minutes.

Stop editing .po files manually

TranslateBot automates Django translations with AI. One command, all your languages, pennies per translation.