Django是一个非常流行和强大的Python Web框架,它提供了很多内置的功能,让开发者可以快速地构建高性能、安全、可扩展的网站。其中一个功能就是国际化和本地化,也就是让网站能够根据用户的语言和地区偏好,显示不同的内容和格式。这样,网站就可以覆盖更多的用户群体,提高用户体验和满意度。
在这篇博客中,我将介绍如何使用Django的国际化和本地化功能,以及一些第三方库,来实现多语言网站的开发。我将以一个简单的博客网站为例,展示如何让它支持英语、法语、西班牙语、越南语、波兰语、泰语、韩语、日语、简体中文和繁体中文这十种语言。我将分为以下几个步骤:
首先,我们需要在项目的settings.py文件中,做一些基本的设置,来启用国际化和本地化功能,以及指定支持的语言和默认语言。具体的设置如下:
# 基本设置
LANGUAGE_CODE = 'zh-hans' # 默认语言,这里我设置为简体中文
#PARLER_DEFAULT_LANGUAGE_CODE = 'zh-hans' # 这是一个第三方库的设置,后面会介绍
TIME_ZONE = 'UTC' # 时区,这里我设置为UTC,你可以根据需要修改
USE_I18N = True # 启用国际化功能
USE_L10N = True # 启用本地化功能
USE_TZ = True # 启用时区支持
# https://github.com/django/django/blob/main/django/conf/global_settings.py#L56
LANGUAGES = ( # 指定支持的语言,这里我设置了十种语言,你可以根据需要增加或删除
('en', ('English')),
('fr', ('Français')),
('es', ('Español')),
('vi', ('Tiếng việt')),
('pl', ('Polskie')),
('th', ('ไทย')),
('ko', ('한국어')),
('ja', ('日本語')),
("zh-hans", ("简体中文")),
("zh-hant", ("繁體中文"))
)
LOCALE_PATHS = [ # 指定存放翻译文件的路径,这里我设置为项目根目录下的locale文件夹
os.path.join(os.path.dirname(os.path.dirname(__file__)), "locale")
]
接下来,我们需要在模型和视图中,标记需要翻译的字符串,这样Django就可以根据用户的语言,显示相应的翻译。在Python文件中,我们可以使用gettext_lazy这个函数,来标记需要翻译的字符串,它会在运行时才进行翻译,而不是在导入时。我们需要在文件开头,导入这个函数,如下:
# 导入gettext_lazy函数
from django.utils.translation import gettext_lazy as _
然后,我们就可以在模型和视图中,使用这个函数,来标记需要翻译的字符串,例如:
# 模型的国际化
from django.db import models
from django.utils.translation import gettext_lazy as _
class Post(models.Model): # 定义一个博客文章的模型
title = models.CharField(_("title"), max_length=200) # 标记标题字段需要翻译
content = models.TextField(_("content")) # 标记内容字段需要翻译
created_at = models.DateTimeField(_("created at"), auto_now_add=True) # 标记创建时间字段需要翻译
updated_at = models.DateTimeField(_("updated at"), auto_now=True) # 标记更新时间字段需要翻译
def __str__(self):
return self.title
class Meta: # 定义模型的元数据
verbose_name = _("post") # 标记模型的名称需要翻译
verbose_name_plural = _("posts") # 标记模型的复数形式需要翻译
# 视图的国际化
from django.shortcuts import render
from django.utils.translation import gettext_lazy as _
from .models import Post
def index(request): # 定义一个首页视图
posts = Post.objects.all() # 获取所有的文章
context = {
"posts": posts,
"title": _("My Blog"), # 标记标题需要翻译
"welcome": _("Welcome to my blog!") # 标记欢迎语需要翻译
}
return render(request, "index.html", context) # 渲染模板
在模板中,我们不能直接使用gettext_lazy这个函数,而是使用{% trans %}和{% blocktrans %}这两个模板标签,来标记需要翻译的字符串。使用这两个模板标签前,需要在模板的最开始处,加载i18n模板库,如下:
<!-- 加载i18n模板库 -->
{% load i18n %}
然后,我们就可以在模板中,使用{% trans %}和{% blocktrans %}这两个模板标签,来标记需要翻译的字符串,例如:
<!-- 模板的国际化 -->
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{% trans "This is a simple blog website that supports multiple languages." %}</p> <!-- 标记这句话需要翻译 -->
<p>{{ welcome }}</p>
<ul>
{% for post in posts %}
<li>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<p>{% blocktrans %}Created at {{ post.created_at }}{% endblocktrans %}</p> <!-- 标记这句话需要翻译,注意变量要放在里面 -->
<p>{% blocktrans %}Updated at {{ post.updated_at }}{% endblocktrans %}</p> <!-- 标记这句话需要翻译,注意变量要放在里面 -->
</li>
{% endfor %}
</ul>
</body>
</html>
为了让URL也能根据用户的语言,显示不同的路径,我们需要在项目的urls.py文件中,做一些修改,来启用URL的国际化。具体的修改如下:
# URL的国际化
from django.conf.urls.i18n import i18n_patterns # 导入i18n_patterns函数
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('rosetta/', include('rosetta.urls')), # 这是一个第三方库的URL,后面会介绍
]
urlpatterns += i18n_patterns( # 使用i18n_patterns函数来添加语言前缀
path('', include('blog.urls')),
prefix_default_language=False # 这个参数表示是否给默认语言也添加前缀,这里我设置为False,表示不添加
)
有时候,我们的静态文件,如图片,也需要根据用户的语言,显示不同的内容。例如,我们可能想要在首页上显示一个欢迎图片,但是图片上的文字需要和用户的语言一致。为了实现这个功能,我们可以使用一个第三方库django-statici18n。它可以根据我们的语言设置,生成不同的静态文件,并且在模板中自动选择正确的文件。
为了使用django-statici18n,我们需要先安装它,然后在settings.py文件中,添加一些设置,如下:
# 静态文件的国际化
# 安装django-statici18n
pip install django-statici18n
# settings.py
INSTALLED_APPS = [
...
'statici18n', # 添加statici18n应用
]
# 配置静态文件的存放路径
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# 配置静态文件的国际化
STATICI18N_ROOT = os.path.join(BASE_DIR, 'blog', 'static') # 指定静态文件的源路径
STATICI18N_OUTPUT_DIR = 'jsi18n' # 指定静态文件的输出目录
然后,我们需要在blog/static目录下,创建一个images目录,用来存放不同语言的图片。我们可以使用一个在线工具,如https://www.canva.com/zh_cn/,来制作图片,并保存为png格式。我们需要为每种语言制作一个图片,并命名为welcome-语言代码.png,例如,英语的图片命名为welcome-en.png,法语的图片命名为welcome-fr.png等。
接下来,我们需要在blog/static目录下,创建一个js目录,用来存放一个JavaScript文件,用于在模板中选择正确的图片。我们可以命名为welcome.js,并写入以下内容:
// welcome.js
// 获取当前语言
var language = document.documentElement.lang;
// 获取图片元素
var image = document.getElementById("welcome-image");
// 根据语言设置图片的源路径
image.src = "/static/images/welcome-" + language + ".png";
最后,我们需要在模板中,引入这个JavaScript文件,并添加一个图片元素,如下:
<!-- 模板中引入静态文件的国际化 -->
{% load i18n %}
{% load static %}
{% load statici18n %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<!-- 引入静态文件的国际化 -->
<script src="{% statici18n LANGUAGE_CODE %}"></script>
<script src="{% static 'js/welcome.js' %}"></script>
</head>
<body>
<h1>{{ title }}</h1>
<p>{% trans "This is a simple blog website that supports multiple languages." %}</p>
<p>{{ welcome }}</p>
<!-- 添加一个图片元素 -->
<img id="welcome-image" alt="{% trans 'Welcome image' %}">
<ul>
{% for post in posts %}
<li>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<p>{% blocktrans %}Created at {{ post.created_at }}{% endblocktrans %}</p>
<p>{% blocktrans %}Updated at {{ post.updated_at }}{% endblocktrans %}</p>
</li>
{% endfor %}
</ul>
</body>
</html>
这样,我们就完成了静态文件的国际化。我们可以运行以下命令,来收集静态文件,并查看效果:
(env)$ python manage.py collectstatic
(env)$ python manage.py runserver
我们会在首页上添加一个语言列表,让用户可以选择不同的语言。我们会使用一些模板标签,如{% get_current_language %}, {% get_available_languages %}, {% get_language_info_list %}等,来获取和显示语言信息。我们还会使用一个自定义的过滤器,url_remove_language,来移除URL中的语言前缀,以便在切换语言时不会跳转到首页。
为了实现语言切换功能,我们需要在blog/templates目录下,创建一个base.html文件,用来作为所有模板的基础模板。我们可以在这个文件中,添加一个语言列表,如下:
<!-- base.html -->
{% load i18n %}
{% load static %}
{% load statici18n %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<!-- 引入静态文件的国际化 -->
<script src="{% statici18n LANGUAGE_CODE %}"></script>
<script src="{% static 'js/welcome.js' %}"></script>
</head>
<body>
<!-- 添加一个语言列表 -->
<ul>
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}[^1^][1]
{% for language in languages %}
<li>
<a href="/{{ language.code }}{{ request.get_full_path|url_remove_language }}" {% if language.code == LANGUAGE_CODE %}style="font-weight:bold"{% endif %}>
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
{% block content %}{% endblock %}
</body>
</html>
注意,我们使用了一个自定义的过滤器,url_remove_language,来移除URL中的语言前缀,以便在切换语言时不会跳转到首页。为了创建这个过滤器,我们需要在blog目录下,创建一个templatetags目录,并在其中创建一个custom_filters.py文件,用来存放自定义的过滤器。我们可以在这个文件中,写入以下内容:
# custom_filters.py
import re
from django import template
register = template.Library()
# 自定义语言过滤器
@register.filter(name="url_remove_language")
def url_remove_language(arg):
pattern = r'^/[a-z]{2}(-[a-z]{2,4})?/'
return re.sub(pattern, '/', arg)
然后,我们需要在index.html文件中,继承base.html文件,并修改一些内容,如下:
<!-- index.html -->
{% extends "base.html" %}
{% load i18n %}
{% load static %}
{% block title %}
{{ title }}
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p>{% trans "This is a simple blog website that supports multiple languages." %}</p>
<p>{{ welcome }}</p>
<!-- 添加一个图片元素 -->
<img id="welcome-image" alt="{% trans 'Welcome image' %}">
<ul>
{% for post in posts %}
<li>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<p>{% blocktrans %}Created at {{ post.created_at }}{% endblocktrans %}</p>
<p>{% blocktrans %}Updated at {{ post.updated_at }}{% endblocktrans %}</p>
</li>
{% endfor %}
</ul>
{% endblock %}
这样,我们就完成了语言切换功能。我们可以刷新网页,看到不同的语言选项,并且可以在不同的语言之间切换。
除了Django自带的国际化和本地化功能,我们还可以使用一些第三方库,来增强我们的多语言网站的开发。在这篇博客中,我们介绍了两个第三方库,分别是Rosetta和django-parler。
Rosetta是一个可以让你在Django管理站点的同一个界面中编辑翻译的库。它可以让你轻松地编辑.po文件,并且会自动更新编译后的翻译文件,无需手动运行命令。它还可以让你使用Google翻译或Microsoft翻译来自动翻译字符串,节省你的时间和精力。
为了使用Rosetta,我们需要先安装它,然后在settings.py文件中,添加一些设置,如下:
# 安装Rosetta
pip install django-rosetta
# settings.py
INSTALLED_APPS = [
...
'rosetta', # 添加rosetta应用
]
# 配置Rosetta
ROSETTA_WSGI_AUTO_RELOAD = True # 设置为True,表示在保存翻译后,自动重载WSGI服务器
ROSETTA_UWSGI_AUTO_RELOAD = True # 设置为True,表示在保存翻译后,自动重载uWSGI服务器
ROSETTA_GOOGLE_TRANSLATE = True # 设置为True,表示启用Google翻译
ROSETTA_GOOGLE_TRANSLATE_API_KEY = 'your-api-key' # 设置Google翻译的API密钥,你需要先申请一个
# ROSETTA_MICROSOFT_TRANSLATOR = True # 设置为True,表示启用Microsoft翻译
# ROSETTA_MICROSOFT_TRANSLATOR_API_KEY = 'your-api-key' # 设置Microsoft翻译的API密钥,你需要先申请一个
然后,我们需要在项目的urls.py文件中,添加一个URL,如下:
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('rosetta/', include('rosetta.urls')), # 添加rosetta的URL
]
接下来,我们就可以在浏览器中,访问http://127.0.0.1:8000/rosetta/,看到Rosetta的界面。我们可以在这里选择不同的语言,编辑和保存翻译,以及使用自动翻译功能。
django-parler是一个可以让你翻译模型的库。由于Django本身不支持翻译模型,所以我们需要使用这个库。它会为每个包含翻译的模型创建一个单独的数据库表。这个表包含所有的翻译字段,以及一个外键来链接原始对象。django-parler提供了一个TranslatableModel模型类和一个TranslatedFields包装器来翻译模型字段。2它还提供了一个TranslatableAdmin类来在Django管理站点中管理翻译。
为了使用django-parler,我们需要先安装它,然后在settings.py文件中,添加一些设置,如下:
# 安装django-parler
pip install django-parler
# settings.py
INSTALLED_APPS = [
...
'parler', # 添加parler应用
]
# 配置parler
PARLER_LANGUAGES = {
None: (
{'code': 'en',},
{'code': 'fr',},
{'code': 'es',},
{'code': 'vi',},
{'code': 'pl',},
{'code': 'th',},
{'code': 'ko',},
{'code': 'ja',},
{'code': 'zh-hans',},
{'code': 'zh-hant',},
),
'default': {
'fallback': 'zh-hans', # 默认的回退语言,这里我设置为简体中文
'hide_untranslated': False, # 是否隐藏未翻译的内容,这里我设置为False,表示显示
}
}
然后,我们需要在模型中,使用django-parler提供的类和包装器,来翻译模型字段,如下:
# 模型的翻译
from django.db import models
from django.utils.translation import gettext_lazy as _
from parler.models import TranslatableModel, TranslatedFields # 导入django-parler提供的类和包装器
class Post(TranslatableModel): # 继承TranslatableModel类
translations = TranslatedFields( # 使用TranslatedFields包装器来定义翻译字段
title = models.CharField(_("title"), max_length=200), # 标记标题字段需要翻译
content = models.TextField(_("content")), # 标记内容字段需要翻译
)
created_at = models.DateTimeField(_("created at"), auto_now_add=True) # 不需要翻译的字段,直接定义在模型中
updated_at = models.DateTimeField(_("updated at"), auto_now=True) # 不需要翻译的字段,直接定义在模型中
def __str__(self):
return self.title
class Meta: # 定义模型的元数据
verbose_name = _("post") # 标记模型的名称需要翻译
verbose_name_plural = _("posts") # 标记模型的复数形式需要翻译
最后,我们需要在admin.py文件中,使用django-parler提供的类,来注册模型,并管理翻译,如下:
# 管理站点的翻译
from django.contrib import admin
from parler.admin import TranslatableAdmin # 导入django-parler提供的类
from .models import Post
@admin.register(Post)
class PostAdmin(TranslatableAdmin): # 继承TranslatableAdmin类
list_display = ('title', 'created_at', 'updated_at') # 定义列表显示的字段
list_filter = ('translations__language_code',) # 定义列表过滤的字段,注意要加上translations__前缀
search_fields = ('translations__title', 'translations__content') # 定义搜索的字段,注意要加上translations__前缀
这样,我们就完成了模型的翻译。我们可以运行以下命令,来创建和更新数据库表,并查看效果:
(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
(env)$ python manage.py createsuperuser
(env)$ python manage.py runserver
zh_Hant
, 如果是zh_hant
好像不工作。
还没有人评论,抢个沙发吧...