Django 多语言实现详解

一、多语言实现原理

Django 的多语言支持基于以下核心原理:

  1. 国际化(i18n):使应用程序能够适应不同语言和地区
  2. 本地化(l10n):为特定语言和地区提供翻译和格式
  3. 翻译系统:通过 gettext 工具链提取和编译翻译字符串
  4. 中间件:检测用户语言偏好并设置相应语言环境
  5. 模板和视图:在代码中标记可翻译文本

二、一步步实现过程

步骤 1:配置 Django 设置

# settings.py

# 1. 启用国际化支持
USE_I18N = True
USE_L10N = True

# 2. 设置支持的语言
LANGUAGES = [
    ('en', 'English'),
    ('zh-hans', '简体中文'),
    ('zh-hant', '繁體中文'),
    ('ja', '日本語'),
]

# 3. 设置默认语言
LANGUAGE_CODE = 'en'

# 4. 指定翻译文件位置
LOCALE_PATHS = [
    os.path.join(BASE_DIR, 'locale'),
]

# 5. 添加中间件(确保在SessionMiddleware之后)
MIDDLEWARE = [
    # ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',  # 语言中间件
    'django.middleware.common.CommonMiddleware',
    # ...
]

步骤 2:标记可翻译文本

在 Python 代码中:

# views.py
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy

def my_view(request):
    # 普通翻译
    output = _("Welcome to my site.")
    
    # 带变量的翻译
    name = "John"
    output = _("Hello, %(name)s") % {'name': name}
    
    # 复数形式
    count = 3
    output = ngettext(
        'There is %(count)d item',
        'There are %(count)d items',
        count
    ) % {'count': count}
    
    return HttpResponse(output)

# models.py
from django.db import models
from django.utils.translation import gettext_lazy as _

class Product(models.Model):
    name = models.CharField(_("Product name"), max_length=100)
    description = models.TextField(_("Product description"))
    
    class Meta:
        verbose_name = _("Product")
        verbose_name_plural = _("Products")

在模板中:

<!-- 加载 i18n 标签 -->
{% load i18n %}

<!-- 简单翻译 -->
<h1>{% trans "Welcome" %}</h1>

<!-- 带变量的翻译 -->
<p>{% trans "Hello" %} {{ user.name }}</p>
<p>{% blocktrans with username=user.username %}
    Welcome, {{ username }}!
{% endblocktrans %}</p>

<!-- 带过滤器的翻译 -->
<p>{{ product.name|title }}</p>

<!-- 复数形式 -->
<p>
{% blocktrans count counter=cart.items.count %}
    There is {{ counter }} item in your cart.
{% plural %}
    There are {{ counter }} items in your cart.
{% endblocktrans %}
</p>

<!-- 在模板中设置语言 -->
<form action="{% url 'set_language' %}" method="post">
    {% csrf_token %}
    <input name="next" type="hidden" value="{{ request.path }}">
    <select name="language">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}
            <option value="{{ language.code }}" 
                    {% if language.code == LANGUAGE_CODE %}selected{% endif %}>
                {{ language.name_local }} ({{ language.code }})
            </option>
        {% endfor %}
    </select>
    <input type="submit" value="Go">
</form>

步骤 3:提取翻译字符串

# 1. 创建 locale 目录(如果不存在)
mkdir -p locale

# 2. 提取所有可翻译字符串到 .po 文件
# Django 会扫描所有模板和代码文件
django-admin makemessages -l zh_hans  # 简体中文
django-admin makemessages -l zh_hant  # 繁体中文
django-admin makemessages -l ja       # 日语

# 针对特定目录
django-admin makemessages -l zh_hans -i venv  # 排除 venv 目录

# 重新提取所有语言
django-admin makemessages -a

步骤 4:翻译 .po 文件

.po 文件示例:

# locale/zh_hans/LC_MESSAGES/django.po

msgid "Welcome to my site."
msgstr "欢迎来到我的网站。"

msgid "Hello, %(name)s"
msgstr "你好,%(name)s"

# 复数形式
msgid "There is %(count)d item"
msgid_plural "There are %(count)d items"
msgstr[0] "有 %(count)d 个项目"
msgstr[1] "有 %(count)d 个项目"

步骤 5:编译翻译文件

# 编译所有 .po 文件为 .mo 文件(机器可读格式)
django-admin compilemessages

# 针对特定语言
django-admin compilemessages -l zh_hans

步骤 6:配置 URL 和语言切换

# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
from django.views.i18n import set_language

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

# 使用 i18n_patterns 为不同语言创建URL前缀
urlpatterns += i18n_patterns(
    path('', home_view, name='home'),
    path('about/', about_view, name='about'),
    # 这些URL会自动添加语言前缀,如 /en/about/, /zh-hans/about/
)

步骤 7:实现语言切换视图

# views.py
from django.conf import settings
from django.http import HttpResponseRedirect
from django.utils import translation

def set_language_view(request, language_code):
    # 验证语言代码是否在支持的语言列表中
    if language_code in dict(settings.LANGUAGES).keys():
        # 设置用户会话中的语言偏好
        request.session[translation.LANGUAGE_SESSION_KEY] = language_code
        
        # 设置 cookie(可选)
        response = HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
        response.set_cookie(
            settings.LANGUAGE_COOKIE_NAME,
            language_code,
            max_age=settings.LANGUAGE_COOKIE_AGE,
            path=settings.LANGUAGE_COOKIE_PATH,
            domain=settings.LANGUAGE_COOKIE_DOMAIN,
        )
        return response
    
    return HttpResponseRedirect('/')

三、高级功能和最佳实践

1. 翻译模型数据

# 使用 django-modeltranslation
# 安装:pip install django-modeltranslation

# 创建 translation.py
from modeltranslation.translator import translator, TranslationOptions
from .models import Product

class ProductTranslationOptions(TranslationOptions):
    fields = ('name', 'description',)

translator.register(Product, ProductTranslationOptions)

2. JavaScript 国际化

// 在模板中
<script src="{% url 'javascript-catalog' %}"></script>

// 使用
const text = gettext('Welcome');
const ntext = ngettext('item', 'items', count);

3. 时区和本地化格式

# settings.py
USE_TZ = True
TIME_ZONE = 'Asia/Shanghai'

# 格式化本地化
from django.utils.formats import date_format, number_format
localized_date = date_format(date_obj)
localized_number = number_format(1234.56)

4. 检测用户语言偏好

# 基于浏览器设置
def get_client_language(request):
    return request.META.get('HTTP_ACCEPT_LANGUAGE', '')

# 基于用户设置(如果有用户系统)
if request.user.is_authenticated and request.user.language_preference:
    language = request.user.language_preference

四、常见问题解决

  1. 翻译不生效

    • 检查 LOCALE_PATHS 配置
    • 确保 .mo 文件已编译
    • 重启开发服务器
  2. 缺少翻译字符串

    • 重新运行 makemessages
    • 检查代码中是否使用了正确的翻译函数
  3. URL 语言前缀问题

    • 确保使用 i18n_patterns
    • 检查 LocaleMiddleware 顺序
  4. 性能优化

    • 使用缓存存储翻译
    • 避免在循环中进行翻译

五、工作流程总结

  1. 开发阶段:使用 gettext(){% trans %} 标记所有用户可见文本
  2. 提取阶段:使用 makemessages 生成 .po 文件
  3. 翻译阶段:翻译人员编辑 .po 文件
  4. 编译阶段:使用 compilemessages 生成 .mo 文件
  5. 部署阶段:配置服务器,确保语言中间件正常工作
  6. 维护阶段:更新翻译时重复步骤 2-4

这样,Django 就能根据用户的语言偏好自动提供相应语言的界面和内容了。
(來自deepseek)

标签: none