使用Python3中的gettext模块翻译Python源码以支持多语言

你写了一个Python 3程序,还想要它适用于其他语言。你能复制全部代码库,然后刻意地检查每个.py文件,替换掉所有找到的文本字符串。但这意味着你有两份你代码的独立副本,每当你要做出个改动或修复个bug,你的工作量会加倍。而且如果你想要程序还适用于其他语言,就更糟了。

幸运的是,Python给了一个解决办法,就是用gettext模块。
一个Hack解法

你应该把你自己的解决办法统一改变。例如,你可以把你程序中的每个字符串替换为一个函数调用(函数名简单些,比如像_()一样),这会返回被翻译为该正确语言的字符串。举个例子,如果你的程序原本是:

print('Hello world!')

……你可以将它改为:

print(_('Hello world!'))

……函数_()会返回'Hello world!'的翻译,它基于程序设置有的语言。比如,如果这个语言设置之前被存在一个叫LANGUAGE的全局变量中,函数_()看起来像这样:

def _(s):
  spanishStrings = {'Hello world!': 'Hola Mundo!'}
  frenchStrings = {'Hello world!': 'Bonjour le monde!'}
  germanStrings = {'Hello world!': 'Hallo Welt!'}

  if LANGUAGE == 'English':
    return s
  if LANGUAGE == 'Spanish':
    return spanishStrings[s]
  if LANGUAGE == 'French':
    return frenchStrings[s]
  if LANGUAGE == 'German':
    return germanStrings[s]

这可以,但是你这是在重复造轮子。Python的gettext模块可以做更多。gettext是一系列工具,文件格式在20世纪90年代被发明出来,来规范软件国际化(也叫I18N)。gettext是个作为对于所有编程语言的系统化的设计,但是我们会在本篇文章中只专注于Python。
程序例子

设想你有个想要翻译的用Python3写的简单“猜数字”游戏。程序的源代码在这里。有四步来使这个程序国际化:

调整这个.py文件的源代码,这样使字符串输入进一个名为_()的函数。
    用和Python一起安装的pygettext.py文本,从源代码创建一个”pot”文件。
    用这个免费的跨平台Poedit软件,从pot文件创建.po和.mo文件。
    再次调整你的.py文件源代码导入gettext模块的代码,设置语言。

第一步:添加 _() 函数

首先,检查你程序中的所有需要被翻译和用_()的调用来替代的字符串。针对Python使用的gettext系统用_()作为得到翻译了的字符串的通用名,因为它是个短名。

注意:用格式型字符串而不是连接型字符串会是你的程序翻译起来更简单。例如,用连接型字符串你的程序会像这样:

print('Good job, ' + myName + '! You guessed my number in ' + guessesTaken + ' guesses!')
print(_('Good job, ') + myName + _('! You guessed my number in ') + guessesTaken + _(' guesses!'))

This results in three separate strings that need to be translated, as opposed to the single string needed in the string formatting approach:
这会导致三个独立的字符串都需要翻译,然而相反的是在格式型的字符串中,只需翻译一个字符串:

print('Good job, %s! You guessed my number in %s guesses!' % (myName, guessesTaken))
print(_('Good job, %s! You guessed my number in %s guesses!') % (myName, guessesTaken))

当你改完“猜数字”源代码后,它会像这样。你并不能运行它,因为_()函数还没定义。这个变化只是让pygettext.py文本可以找到所有需要翻译的字符串。
第二步:用pygettext.py提取字符串

在你Python安装(Windows上的C:Python34Toolsi18n)中的Tools/i18n就是pygettext.py文本。对于可译字符串普通 gettext unix 命令解析 C/C++ 源码并且 xgettext unix 命令可以解析其他语言,而pygettext.py则知道怎样去解析Python源码。它会找到所有字符串并产生个”pot”文件。

在Windows上我已经运行了这个文本像这样:

C:>py -3.4 C:Python34Toolsi18npygettext.py -d guess guess.py

这创建了一个pot文件,叫guess.pot。这只是个普通纯文本文件,它列出来了全部的在源码中寻找_()的调用的要翻译的字符串。你可以在这儿看guess.pot文件.
第三步:用Poedit翻译字符串

你可以用文本编辑器填写翻译但是免费的Poedit软件会更容易从这儿下载http://poedit.net. 选择 > New from POT/PO file… 然后选择你的guess.po文件。

Poedit会问你想要翻译成什么语言。我们举例用西班牙语:

填写翻译吧。(我用 http://translate.google.com,所以对于真的使用西班牙语的人会感觉有点奇怪。)

现在储存文件在它的gettext形式的文件夹里。保存会创建.po文件(一个人类可读的文本文件不同于原始.pot文件,除了是有西语翻译的)和一个.mo文件(一个gettext会读取的机器可读版本。这些文件会存在一个特定的文件夹内,为的是让gettext能够找到他们。他们看起来像这样(比如西语文件中的”es”和德语文件中”de”):

./guess.py
./guess.pot
./locale/es/LC_MESSAGES/guess.mo
./locale/es/LC_MESSAGES/guess.po
./locale/de/LC_MESSAGES/guess.mo
./locale/de/LC_MESSAGES/guess.po

这些两种性质的语言像西语中的”es”和德语中的 ”de” 被称作ISO 639-1 codes是语言的标准缩写。你不一定要用他们,但是遵循标准是有道理的。
第四步:给你程序加上gettext代码

现在你有包含翻译的.mo文件,调整你的Python代码去用它。在你的程序中加上下面的:

import gettext
es = gettext.translation('guess', localedir='locale', languages=['es'])
es.install()

第一个 'guess' 是”定义域”,这其实是意味着guess.mo文件名中“猜”的部分。 localedir是你创建的locale文件夹的目录地址。这会是相对或绝对的路径。'es'描述在locale文件夹下面的文件。LC_MESSAGES文件夹是个标准名

install()方法会导致调用_()返回翻译为西语的字符串。如果你想回到原始的英语只需要分配一个lambda函数值给_,这会返回当时输入的字符串:

import gettext
es = gettext.translation('guess', localedir='locale', languages=['es'])
print(_('Hello! What is your name?')) # prints Spanish

_ = lambda s: s

你可以检查准备翻译的”Guess the Number”源码。如果你想要运行此程序,下载并解压这个压缩文件和它的locale文件夹和.mo安装文件。
延伸阅读

我怎样都称不上是 I18N or gettext的专家,如果我的教程讲解不够好,请一定要留言。大多数情况下,你的软件运行时不会转换语言,而是会去读LANGUAGE,LC_ALL,LC_MESSAGES,和LANG这些环境变量中的一个来确定计算机的工作地点。我会边学习边更新本教程的。

(0)

相关推荐

  • 用Python编写一个基于终端的实现翻译的脚本

    为什么写这个程序,为什么不给这个程序配备gui?原因很简单,因为我是一个命令行控,Linux习惯了不习惯了鼠标,总觉得点着不如敲命令快,各位在看这篇文章就说明和本人有相同的爱好.这个用python写的翻译工具是通过google来实现的,由于google返回的数据不是很规范(或者说我没有找到规律),现在前三项能正常显示(源词,翻译结果,和汉语拼音).下面的词性和其他释义可能不同,见谅,望大神可以指点下小弟和帮小弟完善,这里赶紧不尽. 好了不费话了,下面放代码: #!/usr/bin/env pyt

  • 使用Python从有道词典网页获取单词翻译

    从有道词典网页获取某单词的中文解释. import re import urllib word=raw_input('input a word\n') url='http://dict.youdao.com/search?q=%s'%word content=urllib.urlopen(url) pattern=re.compile("</h2.*?</ul>",re.DOTALL) result=pattern.search(content.read()).gro

  • python使用百度翻译进行中翻英示例

    利用百度词典进行中翻英 复制代码 代码如下: import urllib2import reimport sys reload(sys)sys.setdefaultencoding('utf-8')def tran(word):    url='http://dict.baidu.com/s?wd={0}&tn=dict'.format(word)    print url    req=urllib2.Request(url)    resp=urllib2.urlopen(req)    r

  • python3使用urllib示例取googletranslate(谷歌翻译)

    复制代码 代码如下: #!/usr/bin/env python3# -*- coding: utf-8 -*-# File Name : gt1.py# Purpose :# Creation Date : 1390366260# Last Modified : Wed 22 Jan 2014 06:14:11 PM CST# Release By : Doom.zhou import urllib.requestimport sys typ = sys.getfilesystemencodi

  • python在命令行下使用google翻译(带语音)

    说明 1. 使用google翻译服务获得翻译和语音;2. 使用mplayer播放获得的声音文件,因此,如果要播放语音,请确保PATH中能够找到mplayer程序,如果没有mplayer,请将use_tts设置为False运行.即:main(use_tts=False)3. 退出程序,输入"x",回车. 复制代码 代码如下: #! /usr/bin/env python#coding=utf-8 import requests def translate(words):    impor

  • python翻译软件实现代码(使用google api完成)

    复制代码 代码如下: # -*- coding: utf-8 -*- import httplibfrom urllib import urlencodeimport re def out(text):    p = re.compile(r'","')    m = p.split(text)    print m[0][4:].decode('UTF-8').encode('GBK') if __name__=='__main__':    while True:        w

  • 使用Python3中的gettext模块翻译Python源码以支持多语言

    你写了一个Python 3程序,还想要它适用于其他语言.你能复制全部代码库,然后刻意地检查每个.py文件,替换掉所有找到的文本字符串.但这意味着你有两份你代码的独立副本,每当你要做出个改动或修复个bug,你的工作量会加倍.而且如果你想要程序还适用于其他语言,就更糟了. 幸运的是,Python给了一个解决办法,就是用gettext模块. 一个Hack解法 你应该把你自己的解决办法统一改变.例如,你可以把你程序中的每个字符串替换为一个函数调用(函数名简单些,比如像_()一样),这会返回被翻译为该正确

  • python3中os.path模块下常用的用法总结【推荐】

    abspath 返回一个目录的绝对路径 Return an absolute path. >>> os.path.abspath("/etc/sysconfig/selinux") '/etc/sysconfig/selinux' >>> os.getcwd() '/root' >>> os.path.abspath("python_modu") '/root/python_modu' basename 返回一个

  • python自动化测试中装饰器@ddt与@data源码深入解析

    目录 一.使用ddt和data装饰器的大致框架如下,每个test_开头的方法,代表一条测试用例 二.给类动态的增加方法 案例1 案例2: 案例3: 三.ddt和data的源码解析 原因: 解决: 分部解析代码 总结 一.使用ddt和data装饰器的大致框架如下,每个test_开头的方法,代表一条测试用例 from ddt import ddt,data import unittest test_datas=[ {'id':1,'title':'测试用例1'}, {'id':2,'title':'

  • Python源码加密与Pytorch模型加密分别介绍

    目录 前言 一.python源代码的保护 二.pytorch模型.pth的加密 前言 深度学习领域,常常用python写代码,而且是建立在一些开源框架之上,如pytorch.在实际的项目部署中,也有用conda环境和python代码去部署服务器,在这个时候,又分为两种情况. 部署方式可分为两种,一种是在线部署,算法服务器归公司所有,只开放API给客户,客户通过POST请求访问算法服务器,上传数据并得到返回结果.这种情况客户当然看不到代码.还有一种是离线部署,就是给客户私有化部署,把公司的代码放到

  • 神经网络python源码分享

    神经网络的逻辑应该都是熟知的了,在这里想说明一下交叉验证 交叉验证方法: 看图大概就能理解了,大致就是先将数据集分成K份,对这K份中每一份都取不一样的比例数据进行训练和测试.得出K个误差,将这K个误差平均得到最终误差 这第一个部分是BP神经网络的建立 参数选取参照论文:基于数据挖掘技术的股价指数分析与预测研究_胡林林 import math import random import tushare as ts import pandas as pd random.seed(0) def getD

  • python源码剖析之PyObject详解

    一.Python中的对象 Python中一切皆是对象. ----Guido van Rossum(1989) 这句话只要你学过python,你就很有可能在你的Python学习之旅的前30分钟就已经见过了,但是这句话具体是什么意思呢? 一句话来说,就是面向对象中的"类"和"对象"在Python中都是对象.类似于int对象的类型对象,实现了"类的概念",对类型对象"实例化"得到的实例对象实现了"对象"这个概念.

  • Python源码解析之List

    一.列表结构体 创建列表C语言底层的结构体 lists = [] list.append('name') list.append('age') list.append('grade') typedef struct{ struct _object *_ob_next; struct _object *_ob_prev; // python内部将对象放在链表进行内存管理 Py_ssize_t ob_refcnt; // 引用计数器,就是多少变量用了它 PyObject **ob_item; //

  • Python源码学习之PyType_Type和PyBaseObject_Type详解

    PyType_Type和PyBaseObject_Type PyObject和PyTypeObject内容的最后指出下图中对实例对象和类型对象的理解是不完全正确的, 浮点类型对象全局唯一,Python在C语言层面实现过程中将其定义为一个全局静态变量,定义于Object/floatobject.c中,命名为PyFloat_Type. PyTypeObject PyFloat_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "float&quo

  • Python源码学习之PyObject和PyTypeObject

    前言 Python是C语言实现的,因此Python对象在C语言层面应该是一个结构体 ,组织对象占用的内存. 不同类型的对象,数据及行为均可能不同,因此可以大胆猜测:不同类型的对象由不同的结构体表示. 对象也有一些共性,比如每个对象都需要有一个引用计数,用于实现垃圾回收机制.因此,还可以进一步猜测:表示对象的结构体有一个公共头部. 一. 实例对象的基石-PyObject和PyVarObject PyObject和PyVarObject本质上是对象的头部信息. 1.1 PyObject结构体 Pyt

  • 公众号接入chatGPT的详细教程 附Python源码

    目录 前置准备 域名配置 服务器配置 公众号配置 点击添加配置 前置准备 一个域名 一台服务器 一个公众号 域名配置 在你的域名服务商新建二级域名并绑定服务器主机IP 服务器配置 上传下面的python文件到你的服务器,并修改代码段中相应位置代码(token.api-key.port) import time from flask import Flask,make_response,request import openai from flask import Flask, request f

随机推荐