Django项目实践2 - Django模板(网页多语种支持/国际化)

http://blog.csdn.net/pipisorry/article/details/45061579

如果你要实现多种语言版本的django网站,如英语和中文的两个网站,lz将介绍一个最快捷的方法。

Note:lz建议不会经常变动的字符如网页表头、title什么的用资源.po文件实现翻译。而admin后台管理员填写的内容在model中设置多个语种的字段,再在views中判断当前请求的语言,来返回相应语种的字段。


Django 国际化简介

国际化 -- Internationalization,i 和 n 之间有 18 个字母,简称 I18N,。本地化 -- localization, l 和 n 之间有 10 个字母,简称 L10N。国际化意味着 Web 产品有适用于任何地方的潜力,针对程序开发人员;本地化则是指使一个国际化的程序为了在某个特定地区使用而进行实际翻译的过程,针对翻译人员而言。

Django 的开发和维护者对 Django 框架本身进行了完全国际化,我们可以在 ./Python2.5/site-packages/django/conf/locale/ 找到相关的语言文件。目前 Django-1.2.1 带着 52 个不同的本地化语言文件发行的,使用户能够方便的使用它现有的管理界面。

Django 国际化的本质就是开发者对需要翻译的字符串进行标记,并对字符串进行相应的翻译。当用户访问该 Web 时,Django 内部框架根据用户使用偏好进行 Web 呈现。

Django 国际化使用的翻译模块是使用 Python 自带的 gettext 标准模块。通过一个到 GNU gettext 消息目录库的接口,这个模块为 Python 程序提供了国际化 (I18N) 和本地化 (L10N)。

开发人员和翻译人员需要完成一下 3 个步骤:

1. 第一步:在 Python 代码和模板中嵌入待翻译的字符串,

2. 第二步:把那些字符串翻译成需要支持的语言,并进行相应的编译

3. 第三步:在 Django settings 文件中激活本地中间件

http://blog.csdn.net/pipisorry/article/details/45061579



安装配置gettext

Django框架具有很好的I18N和L10N的支持,其实现是基于GNU的gettext,所以要想在Django中使用I18N还需要先安装配置gettext。

Windows下的gettext(linux下可能不用安装)

对于那些要提取消息或编译消息文件的人们来说,需要的只有这么多。翻译工作本身仅仅包含编辑这个类型的现存文件,但如果你要创建你自己的消息文件,或想要测试或编译一个更改过的消息文件,你将需要这个gettext公用程序。

1. 从http://sourceforge.net/projects/gettext下载以下zip文件

gettext-runtime-0.17.zip

gettext-tools-0.17.zip

  • 同一文件夹下(e.g.D:\Downloads\Programming\gettext)展开这2个压缩文件中的bin\。(注意目录合并了)

  • 更新系统路径

    • 控制面板>系统>高级>环境变量系统变量列表中,点击Path,点击Edit;D:\Downloads\Programming\gettext\bin加到变量值字段的末尾。

Note:安装时一定要注意版本对应,如django1.7对应版本0.15+;安装可能需要 libiconv-1.9.1.tar.gz
在CMD中验证下我们的配置是否正确 xgettext --version或者gettext --version。
Django项目实践2 - Django模板(网页多语种支持/国际化)_第1张图片
Note:
1. 可能先要用命令CHCP 65001修改cmd编码为utf-8,否则执行gettext --version会出现乱码和死循环打印奇怪字符。(lz也是醉了- -!)[ windows命令行cmd设置和快捷键]
2. 只要 xgettext--version命令正常工作,你亦可使用从别处获得的 gettext的二进制代码。有些版本的0.14.4二进制代码被发现不支持这个命令。 不要试图与Django公用程序一起使用一个 gettext。在一个windows命令提示窗口输入命令 `` xgettext —version ``将导致出现一个错误弹出窗口–“xgettext.exe产生错误并且将被windows关闭”。
3. gettext-tools-X.binzip中的readme提到This package contains Win32 binaries of GNU gettext-tools 0.17.Together with these binaries, you also need the Win32 binaries of GNU gettext-runtime (0.17.1) and of GNU libiconv (1.9.1 or newer).Unpack them in the same directory as this package.7
4. If you don’t have the gettext utilities installed,makemessages will create empty files.



配置

settings.py 里面有一个属性LANGUAGE_CODE = 'en',这里设置了网站默认的语言。

启用i18n

由于settings.py里面的属性支持重写,首先在project的setting.py 文件中启用i18n和l10n,及设置USE_I18N =TRUE和USE_L10N=TRUE,一般情况下这两个值默认是开启状态

如果您不需要国际化支持,那么您可以在您的设置文件中设置 USE_I18N=False 。 如果 USE_I18N 被设为 False ,那么Django会进行一些优化,而不加载国际化支持机制。您也可以从您的 TEMPLATE_CONTEXT_PROCESSORS 设置中移除 'django.core.context_processors.i18n'

[Django的官方文档上的i18n]

http://blog.csdn.net/pipisorry/article/details/47185795



声明需要进行国际化的字符串

这又分为.py文件的国际化和html模板文件的国际化。
py文件的国际化
在.py文件中指定翻译字符串的 4 个主要函数及其用途:

django.utils.translation.ugettext()        指定一个翻译字符串,一般都用于 views.py

No-op翻译django.utils.translation.gettext_noop()

标记一个不需要立即翻译的字符串。 这个串会稍后从变量翻译。使用这种方法的环境是,有字符串必须以原始语言的形式存储(如储存在数据库中的字符串)而在最后需要被 翻译出来(如显示给用户时)。

惰性翻译django.utils.translation.gettext_lazy()

ugettext_lazy() 将字符串作为惰性参照存储,而不是实际翻译 , 一般会用于 models.py。 翻译工作将在字符串在字符串上下文中被用到时进行,比如在 Django 管理页面提交模板时。在 Django 模型中总是无一例外的使用惰性翻译。lazy 是一种延迟计算,使用它表示一种对结果的承诺,但只有当真正需要时才会去计算。只要你不是真是需要,你得到的并不是真正的结果。

django.utils.translation.ungettext()    函数包括三个参数: 单数形式的翻译字符串,复数形式的翻译字符串,和对象的个数(将以 count 变量传递给需要翻译的语言)。

这里强烈要求使用惰性翻译,这样能够有效节省django的性能开支。以下我们以惰性翻译为例举个例子:
from django.utils.translation import gettext_lazy as _
transText = _("please login")

模板文件中的国际化
标签修改有两种{% trans "string" %}和{% blocktrans%},{%endblocktrans %},这两个标签都需要在模板的最开始地方加入 {% load i18n %}

Note:模板中的 {% load %} 标签用于加载已有的模板。在 /usr/local/lib/Python2.5/site-packages/django/templatetags/i18n.py 文件中定义了指定模版中翻译字符串的模板标签。在 django 的模板前加入 {% load i18n %},在 i18n.py 源文件中的定义标签就可以在有 load 语句的模板中使用了。

{% trans "string" %}
{% load i18n %}



Learning Center {% trans "Welcome You" %}--Learn Center
这样,我们就指定了要进行国际化的字符串welcome you,在适当的时机Django就能够将其翻译成相对应的文字。
Note:一般情况下这两个标签没有什么区别,翻译工作都准备就绪了,接下来就是体现到模板上去了,首先加载i18n,在模板文件的头部加入{% load i18n%},下来对于需要i18n支持的字段使用{% trans 'Key' %},这里的Key就是某个msgid。
只有需要翻译的字符串包含了django的变量,我们才不得不使用blocktrans来标识。
翻译的内容中含有参数的情况{% blocktrans%},{%endblocktrans %}
1.)在html中使用模板参数,此时必须使用{% blocktrans %}代替{% trans %},例如:
{% blocktrans %}This string will have {{ value }} inside.{%endblocktrans %}
其中{{ value }}是一个django模板变量,由django在将模板转换成具体的html时传入;
2.)如果要使用模板过滤器来翻译一个模板表达式,需要在翻译的这段文本中将表达式绑定到一个本地变量中:
{% blocktrans with value|filter as myvar %} This will have {{ myvar}} inside. {% endblocktrans %}
myvar就是用来绑定表达式本地变量;filter是django所支持的所有过滤器,下面是个使用length的例子;
例如:有一个模板变量{{ funcname }},在翻译串内需要用到该变量的字符长度:
{% blocktrans with funcname|length as len %}
There is {{ len }} letter in {{ funcname }}.
{% endblocktrans %}
len :本地变量,用来绑定(或者说保存){{funcname}}的长度,然后在作为参数出现在翻译字符串内;
{{ funcname }}: 就是1.)里面所讲的模板变量;
这里又引出了另一个问题,就是如果len大于1怎么办? Good question,its answer is using {%plural %} tag. 简单的说就是把单复数形式的句子都写一遍,用{% plural%}区分开,先写单数形式,再写复数形式,实际翻译时,会自动根据len的值来选择句子,具体如下:
{% blocktrans with funcname|length as len %}
There is only one letter in {{funcname}}.
{% plural %}
There are {{ len }} letters in {{ funcname }}.
{% endblocktrans %}
[ 模板标签的实现原理]

另一种实现-使用template filter[http://simple-is-better.com/news/407]




消息文件 - 翻译文件

制作消息文件

就是为一种语言创建一个信息文件。 信息文件是包含了某一语言翻译字符串和对这些字符串的翻译的一个文本文件。 信息文件以 .po 为后缀名。

这一步的前提是gettext配置好了,然后我们进入到project的根目录创建一个locale的文件夹(如果没有这个文件夹命令会出错)

Note: Changed in Django 1.7:When you run makemessages from the root directory of your project, theextracted strings will be automatically distributed to the proper messagefiles. That is, a string extracted from a file of an app containing a locale directory will go in a message file under that directory.A string extracted from a file of an app without any locale directorywill either go in a message file under the directory listed first in LOCALE_PATHS or will generate an error if LOCALE_PATHSis empty.Django中带有一个工具, bin/make-messages.py ,它完成了这些文件的创建和维护工作。

下面两处处之一运行以下命令:Django项目根目录(包含manage.py的目录。e.g. E:\mine\python_workspace\WebSite\labsite\labsite);您Django应用的根目录。The script should be run from one of two places:The root directory of your Django project (the one that contains manage.py).The root directory of one of your Django apps.

创建或更新一个信息文件

django-admin.py makemessages -l zh

Django项目实践2 - Django模板(网页多语种支持/国际化)_第2张图片

Note:

1. linux/migw使用命令django-admin.py makemessages -l en,如果是在windows环境下需要特别注意,因为这两个命令(+compilemessages)使用了一个windows下默认没有安装的组件,gettext。为在windows下运行,需要下载安装gettext。确保已经安装了gettext,否则出错:

2. windows命令行cmd中要指明路径使用命令pythonD:\python3.4.2/Lib/site-packages/django/bin/django-admin.py makemessages -l en来生成翻译的.po文件

3. zh_CN是所创建的信息文件的语言代码。 在这里,语言代码是以本地格式给出的。 例如,巴西地区的葡萄牙语为pt_BR ,德语de, 澳大利亚地区的德语为de_AT 。lz建议在windows下实现时将zh_CN改成zh,原因见《在settings.py中设置所支持的语言列表》部分Note2

4. 这段脚本遍历你的项目源树或你的应用程序源树并且提取出所有为翻译而被标记的字符串。 它在 locale/LANG/LC_MESSAGES 目录下创建(或更新)了一个信息文件。针对上面的de,应该是locale/de/LC_MESSAGES/django.po

5. 作为默认, django-admin.py makemessages 检测每一个有 .html 扩展名的文件。  以备你要重载缺省值,使用 --extension-e 选项指定文件扩展名来检测。
django-admin.py makemessages -l de -e txt

用逗号和(或)使用-e--extension来分隔多项扩展名:django-admin.py makemessages -l de -e html,txt -e xml

6. locale下子目录的样式有固定格式,如:locale//LC_MESSAGES/。如果是中文,对应的目录就是locale/zh_CN/LC_MESSAGES/。如果是英文,则应该是locale/en/LC_MESSAGES/

7. 为了在django里面使用i18n,po文件名必须为django.po,编译过后必须为django.mo,那么翻译的内容就固定在po文件里了。
8. 也可以自己创建目录在目录中使用python D:/python3.4.2/Tools/i18n/pygettext.py生成翻译文件模版messages.pot,改之,charset=gb2312 Content-Transfer-Encoding: utf8,保存之,文件名改为lang.po.

再参考[python国际化(i18n)和中英文切换]

消息文件错误处理

makemessages时解码错误UnicodeDecodeError:skipped file

windows下,如果html文件(包括注释,不仅仅是trans中的)中存在中文或者奇怪空字符  ,就会出现的错误:UnicodeDecodeError:skipped file

commanderror: errors happened while running msgmerge msgmetge:无法识别的选项“--previous"

解决

1. 如果trans中含有中文,建议将html文档编码改成gbk编码[windows小工具 - 转换文件编码]

2. 如果只是html中有中文(trans中没有),建议将D:\python3.4.2\Lib\site-packages\django\core\management\commands\makemessages.py中91/95行语句改成

with open(orig_file, 'r' if six.PY3 else 'rU', encoding='utf-8') as fp:
with open(os.path.join(self.dirpath, thefile), "w", encoding='utf-8') as fp:
原因及解释

html文件编码与django的解码器不对应,官方文档中提到html必须是utf-8编码的,但还是出现编码错误

lz通过分析django源码,发现UnicodeDecodeError错误来源于 makemessages(D:\python3.4.2\Lib\site-packages\django\core\management\commands\makemessages.py),

从第91行语句可见文件是以系统默认编码打开文件的 with open(orig_file, 'r' if six.PY3 else 'rU') as fp:

在文件D:\python3.4.2\Lib\site-packages\django\utils\encoding.py中print编码值,得到cp936而不是utf-8

DEFAULT_LOCALE_ENCODING = get_system_encoding()
也就是说,django makemessages对 html文件的解码用的是系统的默认编码(linux下utf-8, windows下gbk),而lz是在windows下运行的,返回的编码类型是cp936(cp936即 code page 936(代码页936)是以GBK(国标扩展字符集)为基础的编码。GBK支持繁体字和生僻字。GB2312(国标字符集)只是GBK的一部分。GB2312只支持常用的汉字,而且是简体字。)所以将html改成系统默认的编码(如gbk)就可以makemessages不会出现编码错误了。

IndexError: list index out of range

如果的.py文件中要翻译的字符或者.po文件中存在中文,就会出错:IndexError: list index out of range.可能也要将.po文件改成系统默认的编码。

po文件要以utf-8 w/o bom编码。Django only supports .po files encoded in UTF-8 and without any BOM(Byte Order Mark) so if your text editor adds such marks to the beginning offiles by default then you will need to reconfigure it.

.po消息文件

格式很直观。 每个 .po 文件包含一小部分的元数据,比如翻译维护人员的联系信息,而文件的大部分内容是简单的翻译字符串和对应语言翻译结果的映射关系的列表。

举个例子(详细待翻译字符串设置见前面《声明需要进行国际化的字符串》部分),如果Django应用程序包括一个 "Welcometo mysite." 的待翻译字符串 ,像这样:

_("Welcome to my site.")

则django-admin.py makemessages将创建一个 .po 文件来包含以下片段的消息:

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

Note

1. msgid指示的是等待翻译的字符串,msgstr是需要我们提供的翻译之后的字符串

2. msgid 是在源文件中出现的翻译字符串。 不要做改动。msgstr 是相应语言的翻译结果。 刚创建时它只是空字符串,此时就需要你来完成它,引号中加入欢迎来到我的网站。

3. 作为方便之处,每一个消息都包括:以 # 为前缀的一个注释行并且定位上边的msgid 行,文件名和行号。

4. 对于比较长的信息也有其处理方法。 msgstr (或msgid )后紧跟着的字符串为一个空字符串。 然后真正的内容在其下面的几行。 这些字符串会被直接连在一起。 同时,不要忘了字符串末尾的空格,因为它们会不加空格地连到一起。

若要对新创建的翻译字符串校验所有的源代码和模板,并且更新所有语言的信息文件,可以运行以下命令:
django-admin.py makemessages -a

一个典型的po文件类似一下样式:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGEpackage.
# FIRST AUTHOR , YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-12-21 14:00+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Home"
msgstr "主页"

msgid "News"
msgstr "新闻"
Note:

1. 格式相对比较简单,也是键值对的形式。如果是多行的话,需要使用msgstr""的形式,首行不写东西,在后续的几行写文本,翻译出来的结果会由程序自动把文字组合到一起。
2. 编写完的po文件需要编辑成二进制的mo文件才可以被django使用,django使用了gettext来实现翻译,所以mo格式也是gettext要求的。
3. 在linux下使用msgfmt -o django.modjango.po即可完成转换过程,相当方便,windows下需要下载poEdit这个软件。

[一词多译: Same string with different translation]


编译信息文件

创建信息文件之后,每次对其做了修改,都需要将它重新编译成一种更有效率的形式,供 gettext 使用。可以使用django-admin.pycompilemessages完成。

这个工具作用于所有有效的 .po 文件,创建优化过的二进制 .mo 文件供 gettext 使用。在你可以运行 django-admin.pymakemessages的目录下,运行
django-admin.py compilemessages
Django项目实践2 - Django模板(网页多语种支持/国际化)_第3张图片
Django项目实践2 - Django模板(网页多语种支持/国际化)_第4张图片
Note:执行django-admin.pycompilemessages会将所有的po文件转成便于编译模块处理的*.mo文件;
知道了需要翻译的语言,Django就会相应的去查找mo文件
首先,Django查看setting.py中是否指定了LOCALE_PATHS,如果有,则使用此值。
如果setting中没有指定,则使用project的各个app目录下的locale文件。
如果project的各个app目录下没有locale,Django就会查找project的根目录 ,这也是为什么我们第三步在根目录下创建的原因。
如果根目录底下也没有,Django就会自动加载定义在django\conf\locale中的mo文件。
http://blog.csdn.net/pipisorry/article/details/45061579


Django处理语言偏好

一旦你准备好了翻译,如果希望在Django中使用,那么只需要激活这些翻译即可。在这些功能背后,Django拥有一个灵活的模型来确定在安装和使用应用程序的过程中选择使用的语言。

要设定一个安装阶段的语种偏好,请设定 LANGUAGE_CODE。如果其他翻译器没有找到一个译文,Django将使用这个语种作为缺省的翻译最终尝试。

如果你只是想要用本地语言来运行Django,并且该语言的语言文件存在,只需要简单地设置LANGUAGE_CODE 即可。

如果要让每一个使用者各自指定语言偏好,就需要使用 LocaleMiddlewareLocaleMiddleware 使得Django基于请求的数据进行语言选择,从而为每一位用户定制内容。 它为每一个用户定制内容。

加入一些middleware来支持动态切换语言

使用 LocaleMiddleware需要在MIDDLEWARE_CLASSES中增加django.middleware.locale.LocalMiddleware(此选项用于支持动态国际化)

MIDDLEWARE_CLASSES = (
   'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
)

Note:

1. 中间件的顺序是有影响的,最好按照依照以下要求:保证它是第一批安装的中间件类。因为 LocalMiddleware 要用到session数据,所以需要放在SessionMiddleware 之后,因为需要从Session里面获取一个语言类型。如果你使用CacheMiddleware,把LocaleMiddleware放在它后面。[中间件]

2. 这里需要注意,需要用数据库保存 session。在本实例中用到了 mysql test2 数据库中的 django_session 数据表。我们在 /home/jerry/testsite 目录下运行 Python manage.py syncdb 就能产生 django_session 了。

LocaleMiddleware 按照如下算法确定用户的语言:

  • 首先,在当前用户的 session 的中查找django_language键;

  • 如未找到,它会找寻一个cookie

  • 还找不到的话,它会在 HTTP 请求头部里查找Accept-Language, 该头部是你的浏览器发送的,并且按优先顺序告诉服务器你的语言偏好。 Django会尝试头部中的每一个语种直到它发现一个可用的翻译。

  • 以上都失败了的话, 就使用全局的 LANGUAGE_CODE 设定值。

Note

1. 在上述每一处,语种偏好应作为字符串,以标准的语种格式出现。 例如,巴西葡萄牙语是pt-br。如果一个基本语种存在而亚语种没有指定,Django将使用基本语种。 比如,如果用户指定了de-at (澳式德语)但Django只有针对de 的翻译,那么 de 会被选用。

在settings.py中设置所支持的语言列表

只有在 LANGUAGES 设置中列出的语言才能被选用。 若希望将语言限制为所提供语言中的某些(因为应用程序并不提供所有语言的表示),则将LANGUAGES 设置为所希望提供语言的列表

LANGUAGES = (
    # ('de', 'Deutsch'),
    ('en', 'English'),
    ('zh', '简体中文'),
    # ('zh-cn', '简体中文'),
)
Note:
1. 使用zh-CN,在执行{% get_language_info_list for LANGUAGES as languages%}会出错Unknown language code zh-CN and zh.

You will need to use lower case for your locale language codes for it to work properly. i.e. use

LANGUAGES = (
    ('zh-cn', u'简体中文'), # instead of 'zh-CN'
    ('zh-tw', u'繁體中文'), # instead of 'zh-TW'
)

See the language codes specified in https://code.djangoproject.com/browser/django/trunk/django/conf/global_settings.py. You will see that it useszh-tw instead ofzh-TW.

Finally, the language directories storing the *.po and *.mo files in your locales folder needs to be namedzh_CN andzh_TW respectively for the translations to work properly.[Django: How to add Chinese support to the application]

2. 然而lz亲测,要改成zh才行,不然就算测试出request.LANGUAGE_CODE = zh-cn,也不能完成翻译,点击切换语言没反应!(无语了- -!)

3. 上面这个例子限制了语言偏好只能是中文、德语和英语(包括它们的子语言,如 de-chen-us )。
测试你返回的是哪个语言的html

一旦LocaleMiddleware决定用户的偏好,它会让这个偏好作为request.LANGUAGE_CODE对每一个HttpRequest有效。请随意在你的视图代码中读一读这个值,如在view.py的某个view函数中写入语言测试代码:

def index(request):
    '''
    首页
    '''
    if request.LANGUAGE_CODE == 'en':
        return HttpResponse("You prefer to read english.")
    else:
        return HttpResponse("You prefer to read another language.")
        # return render(request, 'bigdata/index.html', locals())
Note:
1. 尽管settings.py中设置了LANGUAGE_CODE = 'zh-CN',但是 request.LANGUAGE_CODE却是en,可能是lz用的浏览器是英文版的,创建的session或者request中的lang设置成了en。
2. 对于静态翻译(无中间件)而言,此语言在 settings.LANGUAGE_CODE中,而对于动态翻译(中间件),它在 request.LANGUAGE_CODE中。
3. 如果你选择的是用两个不同的html来实现多语种就可以通过上面这个来选择显示的语言。至于 request.LANGUAGE_CODE怎么设置下面可以通过html模板上的一个form实现语言选择和设置。
在view中返回response?对象时可以用两种形式
return render(request, 'bigdata/index_e.html', locals())
return render_to_response('bigdata/index_e.html', locals(), RequestContext(request))
# return render_to_response('bigdata/index_e.html', locals(), context_instance=RequestContext(request))



在你自己的项目中使用翻译

Django使用以下算法寻找翻译:

  • 首先,Django在该视图所在的应用程序文件夹中寻找locale 目录。 若找到所选语言的翻译,则加载该翻译。

  • 第二步,Django在项目目录中寻找 locale 目录。 若找到翻译,则加载该翻译。

  • 最后,Django使用 django/conf/locale 目录中的基本翻译。

以这种方式,你可以创建包含独立翻译的应用程序,可以覆盖项目中的基本翻译。 或者,你可以创建一个包含几个应用程序的大项目,并将所有需要的翻译放在一个大的项目信息文件中。 决定权在你手中。

所有的信息文件库都是以同样方式组织的: 它们是:
  • $APPPATH/locale//LC_MESSAGES/django.(po|mo)

  • $PROJECTPATH/locale//LC_MESSAGES/django.(po|mo)

  • 所有在settings文件中 LOCALE_PATHS 中列出的路径以其列出的顺序搜索/LC_MESSAGES/django.(po|mo)

  • $PYTHONPATH/django/conf/locale//LC_MESSAGES/django.(po|mo)

要创建信息文件,也是使用 django-admin.py makemessages.py 工具,和Django信息文件一样。 需要做的就是进入正确的目录——conf/locale (在源码树的情况下)或者locale/ (在应用程序信息或项目信息的情况下)所在的目录下。 同样地,使用compile-messages.py 生成gettext 需要使用的二进制django.mo 文件。

您亦可运行django-admin.py compilemessages--settings=path.to.settings 来使编译器处理所有存在于您LOCALE_PATHS 设置中的目录。

应用程序信息文件稍微难以发现——因为它们需要 LocaleMiddle 。如果不使用中间件,Django只会处理Django的信息文件和项目的信息文件。

最后,需要考虑一下翻译文件的结构。 若应用程序要发放给其他用户,应用到其它项目中,可能需要使用应用程序相关的翻译。 但是,使用应用程序相关的翻译和项目翻译在使用make-messages 时会产生古怪的问题。它会遍历当前路径下所有的文件夹,这样可能会把应用消息文件里存在的消息ID重复放入项目消息文件中。

最容易的解决方法就是将不属于项目的应用程序(因此附带着本身的翻译)存储在项目树之外。 这样做的话,项目级的make-messages 将只会翻译与项目精确相关的,而不包括那些独立发布的应用程序中的字符串。
http://blog.csdn.net/pipisorry/article/details/45061579



在html模板中设置语言选项设置显示语言

set_language 重定向视图

方便起见,Django自带了一个 django.views.i18n.set_language 视图,作用是设置用户语言偏好并重定向返回到前一页面。

Make sure that the following item is in your TEMPLATE_CONTEXT_PROCESSORS list in your settings file:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.i18n',
    'django.contrib.auth.context_processors.auth',
)

在URLconf中加入下面这行代码来激活这个视图(在urls.py里面配置一个i18n的辅助应用):

(r'^i18n/', include('django.conf.urls.i18n')),

Note:

1. 注意这使得这个视图在 /i18n/setlang/ 中有效

2. 这个视图是通过 GET 方法调用的,在请求中包含了language 参数。 如果session已启用(默认已启用'django.contrib.sessions.middleware.SessionMiddleware',),这个视图会将语言选择保存在用户的session中。 否则,它会以缺省名django_language在cookie中保存这个语言选择。(这个名字可以通过LANGUAGE_COOKIE_NAME设置来改变)

html模板中设置语言选项表格

实现1(推荐,lz亲试)

<form action="{% url 'set_language' %}" method="post">
    {% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}"/>
    <select name="language">
        {% for language in LANGUAGES %}
            <option value="{{ language.0 }}"{% if language.0 == LANGUAGE_CODE %} selected="selected"{% endif %}>
                {{ language.1 }} ({{ language.0 }})
        {% endfor %}
    select>
    <input type="submit" value="Go"/>
form>

Note:

1. 点击"Submit" 按钮, form-data 数据(就是input中的value和select选中的option中的value)就会被送到服务器上的url 'set_language'对应的页面(也可以使用下面实现2中的"/i18n/setlang/".)action启用了django.views.i18n.set_language 视图,它的作用是设置用户语言偏好并重定向返回到前一页面。[html_form_submit]

2. 如果出现错误Forbidden (403)CSRF verification failed. Request aborted.要在

下一行加上 {% csrf_token %}[CSRF verification failed. Request aborted. ]

3.name="next"和name="language"不能改成其它,因为在下面原理中的set_language函数会用到。

4. 第一个input是看不到的,直接向set_language参数request提供next属性,在next的value中指定切换语言后显示的页面,为空时set_language会处理为当前页面的HTTP_REFERER(这个就先当作是原来页面吧)

5.LANGUAGES是在settings.py中设置的全局函数,前面有讲到

6. option中的if应该是选择option中的对应于setting.py的LANGUAGE_CODE语种作为默

实现2

<form action="i18n/setlang/" method="post">
    {% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}"/>
    <select name="language">
        {% for lang in LANGUAGES %}
            <option value="{{ lang.0 }}">{{ lang.1 }}option>
        {% endfor %}
    select>
    <input type="submit" value="Go"/>
form>
这样,在html页面中选择某个语言,就会返回翻译过后的那个html页面,完成了多语种支持。

/i18n/setlang/中的处理函数分析(文件路径D:\python3.4.2\Lib\site-packages\django\views\i18n.py)

def set_language(request):
    """
    Redirect to a given url while setting the chosen language in the session or cookie. The url and the language code need to be specified in the request parameters.
    Since this view changes how the user will see the rest of the site, it must only be accessed as a POST request. If called as a GET request, it will redirect to the page in the request (the 'next' parameter) without changing any state.

    当在 session 或 cookie 中设置所选择的语言时,会重定向到指定的网址。URL 和语言代码需要在 request 的参数中被指定。由于这个视图改变用户如何看到网站的其他部分,它必须只能通过 POST request. 如果调用 GET request, 它将重定向到 request 的那页,但没有任何状态改变。

    """
    next = request.POST.get('next', request.GET.get('next'))
    if not is_safe_url(url=next, host=request.get_host()):
        next = request.META.get('HTTP_REFERER')#using http://127.0.0.1:8000/
        if not is_safe_url(url=next, host=request.get_host()):
            next = '/'
    response = http.HttpResponseRedirect(next)#next is http://127.0.0.1:8000/
    if request.method == 'POST':
        lang_code = request.POST.get('language', None)
        if lang_code and check_for_language(lang_code):
            if hasattr(request, 'session'):
                request.session[LANGUAGE_SESSION_KEY] = lang_code;print(lang_code, 'session')#using this
            else:
                response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code,
                                    max_age=settings.LANGUAGE_COOKIE_AGE,
                                    path=settings.LANGUAGE_COOKIE_PATH,
                                    domain=settings.LANGUAGE_COOKIE_DOMAIN);print(lang_code, 'cookie')
    return response

从上面的代码,可以了解到保存了语言选择后,Django 根据以下算法来重定向页面:

(1)Django 在 POST 数据中寻找 next 参数。

(2)如果 next 参数不存在或为空,Django 尝试重定向页面为 HTML 头部信息中 Referer 的值。

(3)如果 Referer 也是空的,即该用户的浏览器并不发送 Referer 头信息,则页面将重定向到 / (页面根目录)。

这个视图是通过 POST 方法调用的,在请求中包含了 language 参数。所以在前面的模版的 select 的 name 和 id 必须为” language”。

如果 session 已启用(上面提到过默认已启用),这个视图会将语言选择保存在用户的 session 中。 否则,它会以缺省名 django_language 在 cookie 中保存这个语言选择。( 这个名字可以通过 LANGUAGE_COOKIE_NAME 设置来改变 )。



在浏览器中测试

Firefox 语言顺序的选择

工具 - 〉选项 - 〉内容,语言栏这一项选着,将汉语 / 中国 [zh-cn] 移到最上面。这样页面将会根据浏览器的配置,优先中文显示。

Django项目实践2 - Django模板(网页多语种支持/国际化)_第5张图片


其它解决方案

1. Django多语言翻译轻量解决方案:使用localeurl和mothertongue来实现多语言支持,通过localurl实现URL的语言前缀,通过mothertougue来翻译相应的字段。可以对数据库中的内容进行翻译等等,还可以尝试调用google的翻译接口,对一些简单的单词进行翻译,在填入英文时自动翻译成中文。

[Django多语言翻译轻量解决方案]

2. 采用自定义tag的方式定义一个语言选择的下拉框

[django多语言支持]

from: http://blog.csdn.net/pipisorry/article/details/45061579
ref: Internationalization: in template code
Django实现国际化的步骤
Django 国际化实例及原理分析
基于gettext的Django国际化or多国语言支持(Internationlization)
django 实现多语功能
网站需要支持中英文切换的功能-CSDN论坛
python Django模板的使用方法(图文)



你可能感兴趣的:(Django小记,Django)