配置文件,注意中间件插入顺序
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # important for multi language support
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
USE_I18N = True
USE_L10N = True
import os
# 语言包选项
LANGUAGES = (
('en', 'Eng'),
('zh-hans', '简'),
('zh-hant', '繁'),
)
# 编译的语言文件存放路径,我这里是放在了根目录
LOCALE_PATHS = (
os.path.join(BASE_DIR,'locale'),
)
根url文件urls.py
from django.urls import path,re_path,include
urlpatterns = [
path('i18n/',include("django.conf.urls.i18n")),
]
from django.conf.urls.i18n import i18n_patterns
urlpatterns += i18n_patterns(
re_path(r'^$', IndexView.as_view(), name="index"),
)
前端index.html的代码,加了点css的样式
{% load i18n %}
........
{% get_available_languages as LANGUAGES %}
{% for LANGUAGE in LANGUAGES %}
{{LANGUAGE.1}}
{% endfor %}
将需要翻译的内容添加trans标签,例如:
<li><a href="{% url 'index' %}">{% trans "Home" %}</a></li>
生成三种语言对应的内容
django-admin makemessages -l en
django-admin makemessages -l zh_Hans
django-admin makemessages -l zh_Hant
# 快捷方式
django-admin makemessages -l en -l zh_Hans -l zh_Hant
这里一定要注意,生成中文内容要用下划线(具体原因可以参考下方两条官网链接),不要用zh-hans这类,否则翻译无效!!!
将所有的msgstr翻译完成之后,生成mo文件
django-admin compilemessages
再次打开路径就可以了
这个时候可以为语言切换增加对应的url了,官网的教程是以一个form表单提交来进行语言切换,我不想搞得那么复杂,上面index.html的代码中,
{% get_available_languages as LANGUAGES %}
{% for LANGUAGE in LANGUAGES %}
{{LANGUAGE.1}}
{% endfor %}
这个LANGUAGES其实就是我们在配置文件中定义的语言选项,例如按照我上方的配置文件进行到这里,该参数会是一个列表,包含3个元组
[('en', 'Eng'), ('zh-hans', '简'), ('zh-hant', '繁')]
所以LANGUAGE.0和.1分别是语言代码和描述,我们可以将语言代码组合到路径当中,例如
{% for LANGUAGE in LANGUAGES %}
<li><a href="/{{LANGUAGE.0}}">{{LANGUAGE.1}}</a></li>
{% endfor %}
斜杠代表从根域名开始,点击哪个语言就跳转到哪个语言目录下,但是这样有一个问题,就是不管用户在哪个路径下,最后都会跳转到切换语言的首页路径下,用户体验很不好,这个参数的拼接可以自定义过滤器来分解替换,参考上一篇文章的写法即可,也可以换一个思路,因为我们只需要替换语言代码
{% get_current_language as LANGUAGE_CODE %}
{{LANGUAGE_CODE}}
LANGUAGE_CODE其实就是i18n定义下的当前语言代码,我们只需要把它替换掉就可以,考虑完全使用django内置的过滤器来完成
{% get_current_language as LANGUAGE_CODE %}
{% with request.path_info|cut:LANGUAGE_CODE|cut:"//" as cus_info %}
{% for LANGUAGE in LANGUAGES %}
<li><a href="{{request.scheme}}://{{request.get_host}}/{{LANGUAGE.0}}/{{cus_info}}">{{LANGUAGE.1}}</a></li>
{% endfor %}
{% endwith %}
解释一下,上面的LANGUAGE_CODE 为当前语言代码,我定义了一个变量cus_info 来获取当前路径下切除掉语言代码和两个斜杠之后的路径,这里解释一下为什么是cut:"//",首先我们要知道request.path_info的获取到的是一个不包含协议、域名IP端口的路径,类似于/zh-hans/parames,当你切掉当前语言代码时,还剩下//parames,看到这里,是不是觉得切掉两个斜杠有些多余,其实切掉一个斜杠在这例子中也能运行,但是一旦有多个参数,则问题就出现了,例如
/zh-hans/parames1/parames2
切除语言代码之后,如果切除单斜杠,后面的路径就全部错误了。
之后再用拼接的方式将各级协议,host等拼接起来,这样就完成了在当前路径下切换不同语言的功能。
如果当前语言被选中,我们就在前端页面给他增加一个active类,就可以写一些css样式突出显示啦
{% for LANGUAGE in LANGUAGES %}
{% if LANGUAGE.0 == LANGUAGE_CODE %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="{{request.scheme}}://{{request.get_host}}/{{LANGUAGE.0}}/{{cus_info}}">{{LANGUAGE.1}}</a>
</li>
{% endfor %}
也许你会奇怪,明明在配置文件中配置了
LANGUAGE_CODE = 'en'
为什么打开首页还是默认显示简体中文开始,这是因为LocaleMiddleware中间件有自己的判断方式,LANGUAGE_CODE的设置只是最后的尝试,请看官方文档摘录
- LocaleMiddleware 试图通过以下算法来确定用户的语言偏好。
首先,它在请求的URL中寻找语言前缀。 只有当你在你的根 URLconf 中使用 i18n_patterns 函数时,才会这样做。参见 国际化:在 URL 模式中 了解更多关于语言前缀和如何国际化 URL 模式的信息。
- 如果失败,它将查找 cookie。
所使用的 cookie 的名称由 LANGUAGE_COOKIE_NAME 设定。(默认名称是 django_language)。
- 如果失败了,它将查看 Accept-Language HTTP 头。这个头由你的浏览器发送,并告诉服务器你喜欢哪种语言,按优先级排序。Django 会尝试每一种语言,直到找到可用的翻译。
- 如果不行,则使用全局 LANGUAGE_CODE 设置。
注意:
在每一个地方,语言偏好都应该是标准的语言格式,作为一个字符串。例如,巴西葡萄牙语是 pt-br。
如果基本语言可用,但指定的子语言不可用,Django 就使用基本语言。例如,如果用户指定了 de-at (奥地利德语),但 Django 只有 de 可用,Django 就使用 de。
关于“标准的语言格式”
- locale name
区域名称,可以是 ll 形式的语言规范,也可以是 ll_CC 形式的语言和国家组合规范。例如:it、de_AT、es、pt_BR、sr_Latn。语言部分总是用小写。国家部分如果超过两个字符,则首字母大写,否则全部大写。分隔符为下划线。
- language code
代表语言名。浏览器使用这个格式来在 Accept-Language HTTP header 里发送浏览器接受的语言名。比如:it, de-at, es, pt-br 。语言代码一般用小写表示,但是 HTTP Accept-Language header 不区分大小写。用破折号来间隔。
- message file
一个消息文件是文本文件,代表一种语言,包含所有可用的 translation strings ,以及它们如何在给定的语言里表示。消息文件的文件扩展名是 .po 。
- translation string
可以翻译的文字。
- format file
格式文件是一个 Python 模块,用于定义本地数据格式。
更多信息可以通过下方参考第三个链接查阅。
这一点也可以通过切换浏览器的默认语言进行测试,可以看见首页的语言的改变。
参考:
https://docs.djangoproject.com/zh-hans/4.0/topics/i18n/translation/#how-to-create-language-files
https://docs.djangoproject.com/zh-hans/4.0/topics/i18n/#term-locale-name
# django如何发现语言偏好
https://docs.djangoproject.com/zh-hans/4.0/topics/i18n/translation/https://docs.djangoproject.com/zh-hans/4.0/topics/i18n/#term-language-code