YOLO813

Django实战多语言

参考Django制作多语言网站的尝试


配置文件,注意中间件插入顺序

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