블로그로 돌아가기

Django 현지화: 앱을 다국어로 만드는 완벽 가이드

2026-07-10 7분 읽기

영어로 작동하는 Django 앱이 있습니다. 이제 다른 언어에서도 작동하도록 해야 합니다. 이 가이드는 코드에서 문자열을 표시하는 것부터 완전히 현지화된 사이트를 제공하는 것까지 전체 과정을 다루며, 각 단계마다 실용적인 예제를 제공합니다.

Django의 국제화 프레임웤(보통 i18n이라고 불림)은 상당히 잘 만들어진 편입니다. 오른쪽에서 왼쪽으로 쓰는 언어, 복수형 규칙, 날짜 형식, 그리고 현지화를 정말 어렵게 만드는 기타 요소들을 처리합니다. 다만 설정에 여러 구성 요소가 관련되어 있고, 대부분의 튜토리얼은 그 중 한두 가지만 다룹니다.

현지화가 실제로 포함하는 것

현지활는 단순히 문자열을 번역하는 것 이상입니다. 올바르게 현지화된 Django 앱은 다음을 처리합니다:

  • 텍스트 번역 (템플릿, 뷰, 모델, JavaScript)
  • 언어별 URL 라우팅 (/en/about/, /de/about/)
  • 날짜, 시간, 숫자 형식 지정 (14/03/2026 vs 03/14/2026)
  • 복수형 규칙 (영어는 2가지 형태, 아랍어는 6가지, 일본어는 1가지)
  • 아랍어, 히브리어, 페르시아어를 위한 오른쪽에서 왼쪽으로 쓰는 레이아웃
  • 시간대 인식

대부분의 Django 프로젝트는 처음 세 가지만 필효합니다. 하지만 시작하기 전에 프레임워크가 무엇을 할 수 있는지 알아두면, 나중에 막다른 골목에 빠지는 것을 방지할 수 있습니다.

1단계: 설정 구성하기

settings.py애서 국제화 설정부터 시작하세요:

from django.utils.translation import gettext_lazy as _

LANGUAGE_CODE = "en"

USE_I18N = True
USE_L10N = True
USE_TZ = True

LANGUAGES = [
    ("en", _("English")),
    ("de", _("German")),
    ("fr", _("French")),
    ("ja", _("Japanese")),
    ("es", _("Spanish")),
]

LOCALE_PATHS = [
    BASE_DIR / "locale",
]

LANGUAGES는 사이트가 지원하는 언어를 정의합니다. 실제로 번역할 계획이 있는 언어만 포함하세요. 번역하지 않을 30개 언어를 여기에 추가하면 빈 .po 파일만 생기고 URL 구조만 복잡해집니다.

LOCALE_PATHS는 Django에게 번역 파일을 어디서 찾을지 알려줍니다. 기본값은 각 앱 안의 locale/ 디렉토리이지만, 프로젝트 수준의 단일 locale/ 디렉토래가 관리하기 더 쉽습니다.

2단계: 미들웨어와 URL 설정 추가하기

MIDDLEWARE 설정에 로케일 미들웨어를 추가하세요. 순서가 중요합니다:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.locale.LocaleMiddleware",  # after SessionMiddleware
    "django.middleware.common.CommonMiddleware",
    # ...
]

LocaleMiddlewareSessionMiddleware 뒤에(언어 기본 설정을 기억하기 위해 세션이 필요함), CommonMiddleware 앞에 와야 합니다. 이 순서를 잘못 지정하면 Django 번역이 조용히 실패하는 가장 흔한 원인 중 하나입니다.

그런 다음 URL 패턴을 i18n_patterns로 감싸세요:

from django.conf.urls.i18n import i18n_patterns

urlpatterns = [
    path("admin/", admin.site.urls),
]

urlpatterns += i18n_patterns(
    path("", include("myapp.urls")),
)

이렇게 하면 모든 URL 앞에 언어 코드가 붙습니다: /en/about/, /de/about/, /fr/about/. 관리자 페이지는 대부분의 프로젝트에서 현지화가 필요하지 않으므로 접두사가 붙지 않습니다.

3단계: 번역할 문자열 표시하기

대부분의 작업이 이 단계에서 이루어집니다. 코드에서 사용자에게 보이는 모든 문저열을 번역 함수로 감싸야 합니다.

Python 코드에서

from django.utils.translation import gettext as _

def my_view(request):
    message = _("Your order has been placed.")
    return render(request, "order.html", {"message": message})

뷰와 함수에서는 gettext(_로 별칭)를 사용하세요. 모델 필드 레이블과 같은 모듈 수준 문자열에는 gettext_lazy를 사용하세요:

from django.utils.translation import gettext_lazy as _

class Product(models.Model):
    name = models.CharField(_("product name"), max_length=200)
    description = models.TextField(_("description"))

    class Meta:
        verbose_name = _("product")
        verbose_name_plural = _("products")

차이점이 중요합니다: gettext_lazy는 문자열이 실제로 렌더링될 때까지 번역 조회를 지연시킵니다. 이는 임포트 시점에 평가되는 모든 것(모델 정의, 폼 필드, URL 이름)에 필요합니다. 모듈 수준에서 일반 gettext를 사용하면 시작 시 한 번만 번역되어 모든 사용자에게 잘못된 언어를 제공하게 됩니다.

템플릿에서

{% load i18n %}

<h1>{% trans "Welcome to our store" %}</h1>

<p>
    {% blocktrans count items=cart.item_count %}
    You have {{ items }} item in your cart.
    {% plural %}
    You have {{ items }} items in your cart.
    {% endblocktrans %}
</p>

{% trans %}는 단순한 문자열을 처리합니다. {% blocktrans %}는 변수나 복수형이 포함된 문자열을 처리합니다. 이 태그를 사용하는 모든 템플릿 상단에 {% load i18n %}을 잊지 마세요.

JavaScript에서

Django는 번역의 JavaScript 카탈로그를 생성할 수 있습니다:

from django.views.i18n import JavaScriptCatalog

urlpatterns += i18n_patterns(
    path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"),
)

그런 다음 JavaScript에서:

document.getElementById("status").textContent = gettext("Loading...");

gettext를 사용하는 JavaScript보다 먼저 카탈로그 스크립트를 포함하세요:

<script src="{% url 'javascript-catalog' %}"></script>

4단계: .po 파일 생성 및 번역하기

문자열이 표시되면 번역 파일을 생성하세요:

python manage.py makemessages -l de -l fr -l ja -l es

이렇게 하면 locale/ 디렉토리에 .po 파일이 생성됩니다:

locale/
  de/LC_MESSAGES/django.po
  fr/LC_MESSAGES/django.po
  ja/LC_MESSAGES/django.po
  es/LC_MESSAGES/django.po

.po 파일에는 다음과 같은 항목이 포함되어 있습니다:

#: myapp/views.py:12
msgid "Your order has been placed."
msgstr ""

msgstr에 번역이 들어갑니다. 수동으로 입력하거나, 번역가를 고용하거나, AI 번역 도구로 프로세스를 자동화할 수 있습니다.

번역 후, .po 파일을 Django가 효율적으로 읽을 수 있는 바이너리 .mo 파일로 컴파일해야 합니닫:

python manage.py compilemessages

번역을 업데이트할 때마다 compilemessages를 실행하세요. 이 단계를 잊는 것도 번역이 표시되지 않는 흔한 원인입니다. Django는 .po 파일이 아닌 .mo 파일을 읽습니다.

5단계: 날짜, 숫자, 시간 형식 처리하기

Django의 L10N 설정은 날짜와 숫자의 형식을 제어합니다. USE_L10N = True로 설정하면, Django가 자동으료 로케일 인식 형식을 사용합니다:

{% load l10n %}

<p>Order date: {{ order.created_at }}</p>
<p>Total: {{ order.total }}</p>

영어에서 "July 10, 2026"으로 표시되는 날짜는 독일어에서 "10. Juli 2026"으로, 일본어에서 "2026年7月10日"으로 자동 표시됩니다. 숫자도 비슷한 규칙을 따릅니다: 영어에서 1,234.56은 독일어에서 1.234,56이 됩니다.

특정 값의 형식을 재정의해야 하는 경우, localizeunlocalize 필터를 사용하세요:

{% load l10n %}

<!-- Always use locale formatting -->
<p>{{ value|localize }}</p>

<!-- Always use the default (English) format -->
<p>{{ value|unlocalize }}</p>

6단계: 언어 전환기 추가하기

사용자에게 언어를 변겅할 수 있는 방법이 필요합니다. Django의 set_language 뷰와 함께 작동하는 간단한 언어 전환기는 다음과 같습니다:

{% load i18n %}

<form action="{% url 'set_language' %}" method="post">
    {% csrf_token %}
    <input type="hidden" name="next" value="{{ request.path }}">
    <select name="language" onchange="this.form.submit()">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% for lang_code, lang_name in LANGUAGES %}
            <option value="{{ lang_code }}"
                {% if lang_code == LANGUAGE_CODE %}selected{% endif %}>
                {{ lang_name }}
            </option>
        {% endfor %}
    </select>
</form>

URL 설정에 set_language URL이 포함되어 있는지 확인하세요:

urlpatterns = [
    path("i18n/", include("django.conf.urls.i18n")),
    # ...
]

이것은 i18n_patterns 바깥에 있어야 합니다. 언어 전환기 자체에는 언어 접두사가 필요하지 않기 때문입니다.

흔한 실수와 피하는 방법

모델에서 gettext_lazy 대신 gettext 사용하기

이것은 Django 프로젝뜨에서 가장 흔한 현지화 버그입니다. 모델 필드, 폼 레이블, 그리고 모듈 수준에서 정의된 모든 것에는 gettext가 아닌 gettext_lazy가 필요합니다. 증상: 모든 사용자가 서버 프로세스가 시작될 때의 언어로 번역을 보게 됩니다.

compilemessages 실행을 잊는 경우

.po 파일을 편집하고 서버를 재시작했지만 번역이 여전히 표시되지 않습니다. Django가 읽는 것은 .mo 파일이며, 이 파일은 자동으로 업데이트되지 않습니다. 배포 파이프라인에 compilemessages를 추가하세요.

잘못된 미들웨어 순서

LocaleMiddlewareCommonMiddleware 뒤에 있으면 Django가 URL 접두사에서 언어를 감지할 수 없습니다. 요청은 매번 기본 언어로 처리됩니다. SessionMiddlewareCommonMiddleware 사이에 배치하세요.

템플릿에서 하드코딩된 문자열

번역해야 할 문자열을 놓치기 쉽습니다. 템플릿에서 {% trans %} 또는 {% blocktrans %} 태그 바깥에 있는 일반 텍스트를 검색하세요. 흔히 놓치는 것들: 버튼 레이블, 폼 필드 플레이스홀더, 오류 메시지, 푸터 텍스트.

복수형을 처리하지 않는 경우

영어는 두 가지 복수 형태가 있습니다(1 item, 2 items). 러시아어는 세 가지, 아랍어는 여섯 가지가 있습니다. ngettext{% blocktrans count %}를 사용하지 않고 "item(s)"를 하드코딩하면, 다른 언어에서 번역이 어색하거나 문법적으로 올바르겡 않게 됩니다.

번역 워크플로우 자동화

.po 파일을 수동으로 번역하는 것은 소규모 프로젝트에서는 가능하지만 확장성이 없습니다. 5개 언어에 200개의 번역 가능한 문자열이 있는 일반적인 Django 프로젝트는 관리해야 할 번역이 1,000개입니다. 문자열을 추가하거나 변경할 때마다 모든 언어를 업데이트해야 합니다.

워크플로우는 보통 다음과 같습니다:

  1. _() 또는 {% trans %}로 새 문자열 표시
  2. makemessages를 실행하여 추출
  3. .po 파일에서 새 항목 번역
  4. compilemessages 실행
  5. 모든 것을 커밋

3단계와 4단계에서 속도가 느려집니다. 인간 번역가는 지연과 비용을 추가합니다. 번역 서비스에 수동으로 복사하여 붙여넣는 것은 지루하고 오류가 발생하기 쉬우며, 특히 %(name)s{count}와 같은 Django의 플레이스홀더 형식을 보존해야 할 때 더욱 그렇습니다.

AI 번역 도구는 3단계를 자동화하면서 4단계는 CI/CD 파이프라인에 유지할 수 있습니다. 단점은 AI 번역이 뉘앙스와 용어에 대한 검토가 필요할 수 있다는 것이지만, 대부분의 UI 문자열에 대해서는 품질이 바로 배포할 수 있을 만큼 충분히 좋습니다.

현지화 테스트하기

배포하기 전에 현지화가 실제로 작동하는지 확인하세요:

# Generate messages for all configured languages
python manage.py makemessages -a

# Check for missing translations
python manage.py compilemessages

# Start the dev server and switch languages
python manage.py runserver

확인할 사항:

  • 언어 전환기를 사용하여 지원되는 모든 언어 간에 전환하기
  • URL에 올바른 언어 접두사가 포함되어 있는지 확인하기
  • 날짜와 숫자가 로케일별로 올바르게 형식이 지정되는지 확인하기
  • 번역되지 않은 문자열 찾기(영어로 표시됩니닫)
  • 지원하는 경우 오른쪽에서 왼쪽으료 쓰는 언어 테스트하기
  • 복수형이 올바르게 작동하는지 확인하기 (0, 1, 2, 5개 이상의 항목으로 테스트)

.po 파일에 번역되지 않았거나 퍼지(fuzzy) 항목이 있으면 실패하는 CI 검사를 추가하는 것을 고려하세요. 이렇게 하면 번역이 누락된 채로 실수로 배포되는 것을 방지할 수 있습니다.

프로젝트 구조

잘 구성된 현지화 설정은 다음과 같습니다:

myproject/
  locale/
    de/LC_MESSAGES/django.po
    fr/LC_MESSAGES/django.po
    ja/LC_MESSAGES/django.po
    es/LC_MESSAGES/django.po
  myapp/
    templates/
    views.py
    models.py
  settings.py
  urls.py
  TRANSLATING.md

TRANSLATING.md 파일은 선택 사항이지만 유용합니다. 프로젝트의 용어 기본 설정, 어조 가이드라인, 그리고 번역 관련 규칙을 문서화합니다. 컨텍스트 파일을 지원하는 AI 번역 도구를 사용하는 경우, 이 파일을 읽고 기본 설정을 자동으로 적용할 수 있습니다.

다음에 할 일

처음부터 시작하는 경우:

  1. 1단계와 2단계의 설정과 미들웨어를 추가하세요
  2. 가장 중요한 템플릿을 선택하고 문자열을 표시하세요 (3단계)
  3. 먼저 하나의 언어로 .po 파일을 생성하세요 (4단계)
  4. 그 하나의 언어를 번역하고 처음부터 끝까지 작동하는지 확인하세요
  5. 그런 다음 더 많은 템플릿과 언어료 확장하세요

이미 부분적으로 현지화된 앱이 있는 경우:

  1. makemessages -a를 실행하여 모든 .po 파일을 재생성하세요
  2. 퍼지(fuzzy)이거나 번역되지 않은 문자열을 확인하세요
  3. 누락된 번역을 채우세요
  4. 새로 번역되지 않은 문자열이 프로덕션에 도달하기 전에 잡히도록 CI 검사를 설정하세요

작게 시작해서 확장하는 것이 모든 것을 한꺼번에 현지화하려는 것보다 낫습니다. 하나의 언어가 완전히 작동하도록 만든 다음, 더 많은 언어를 추가하세요.

.po 파일 수동 편집 중단

TranslateBot은 AI로 Django 번역을 자동화합니다. 명령 하나로 모든 언어를, 번역당 몇 푼이면 충분합니다.