模块翻译¶
本节说明如何为您的模块提供翻译功能。
注解
如果您想为Odoo本身的翻译做出贡献,请参阅 Odoo Wiki页面 。
导出可翻译术语¶
您的模块中有许多术语是隐式可翻译的。因此,即使您尚未进行任何与翻译相关的特定工作,也可以导出模块的可翻译术语,并可能找到需要处理的内容。
翻译导出通过管理界面完成,登录后端界面并打开
。将语言保留为默认值(新语言/空模板)。
选择 PO文件 格式。
选择您的模块。
点击 导出 并下载文件。

这会生成一个名为 yourmodule.pot
的文件,应将其移动到 yourmodule/i18n/
目录中。该文件是一个 PO模板 ,其中仅列出可翻译字符串,并可基于此创建实际的翻译文件(PO文件)。PO文件可以通过 msginit 创建,使用专用的翻译工具(如 POEdit ),或者简单地将模板复制到一个名为 language.po
的新文件中。翻译文件应放置在 yourmodule/i18n/
目录中,与 yourmodule.pot
并列,并在安装相应语言时由Odoo自动加载(通过 )。
注解
在安装或更新模块时,所有已加载语言的翻译也会被安装或更新。
隐式导出¶
Odoo会自动从“数据”类型的内容中导出可翻译字符串:
在非QWeb视图中,所有文本节点以及
string
、help
、sum
、confirm
和placeholder
属性的内容都会被导出。QWeb模板(包括服务端和客户端),所有文本节点都会被导出,但
t-translation="off"
块中的内容除外,title
、alt
、label
和placeholder
属性的内容也会被导出。对于
Field
,除非其模型标记为_translate = False
:它们的
string
和help
属性会被导出。如果存在
selection
并且是一个列表(或元组),它会被导出。如果它们的
translate
属性设置为True
,则其所有现有值(跨所有记录)都会被导出。
_constraints
和_sql_constraints
的帮助/错误消息会被导出。
显式导出¶
当涉及到Python代码或JavaScript代码中更“命令式”的情况时,Odoo无法自动导出可翻译术语,因此必须通过函数调用来显式标记字面字符串以供导出。
在Python中,包装函数是 odoo.api.Environment._()
和 odoo.tools.translate._()
:
title = self.env._("Bank Accounts")
# old API for backward-compatibility
from odoo.tools import _
title = _("Bank Accounts")
在JavaScript中,包装函数通常是 odoo.web._t()
:
title = _t("Bank Accounts");
警告
只有字面字符串可以标记为导出,表达式或变量则不行。对于字符串格式化的情况,这意味着必须标记格式字符串,而不是格式化后的字符串。
_
和 _t
的惰性版本在Python中是 odoo.tools.translate.LazyTranslate
工厂,在JavaScript中是 odoo.web._lt()
。翻译查找仅在渲染时执行,可用于在类方法或全局变量中声明可翻译属性。
from odoo.tools import LazyTranslate
_lt = LazyTranslate(__name__)
LAZY_TEXT = _lt("some text")
注解
模块的翻译默认情况下不会暴露给前端,因此无法从JavaScript中访问。为了实现这一点,模块名称必须以 website
为前缀(如 website_sale
、 website_event
等),或者通过为 ir.http
模型实现 _get_translation_frontend_modules_name()
显式注册。
示例如下::
from odoo import models
class IrHttp(models.AbstractModel):
_inherit = 'ir.http'
@classmethod
def _get_translation_frontend_modules_name(cls):
modules = super()._get_translation_frontend_modules_name()
return modules + ['your_module']
上下文¶
为了进行翻译,翻译函数需要知道 语言 和 模块 名称。当使用 Environment._
时,语言是已知的,您可以将模块名称作为参数传递,否则它会从调用者中提取。
对于 odoo.tools.translate._
,语言和模块是从上下文中提取的。为此,我们会检查调用者的局部变量。这种方法的缺点是容易出错:我们尝试查找上下文变量或 self.env
,但如果在模型方法之外使用翻译,这些变量可能不存在;也就是说,它在普通函数或Python推导式中不起作用。
惰性翻译在创建期间绑定到模块,并在使用 str()
求值时解析语言。请注意,您还可以将惰性翻译传递给 Environment._
以翻译它,而无需任何隐式的语言解析。
变量¶
不要 这样做,虽然提取可能有效,但文本将无法正确翻译::
_("Scheduled meeting with %s" % invitee.name)
要 将动态变量设置为翻译查找的参数(如果翻译中缺少占位符,这将回退到源文本)::
_("Scheduled meeting with %s", invitee.name)
块¶
不要 将翻译拆分为多个块或多行::
# bad, trailing spaces, blocks out of context
_("You have ") + len(invoices) + _(" invoices waiting")
_t("You have ") + invoices.length + _t(" invoices waiting");
# bad, multiple small translations
_("Reference of the document that generated ") + \
_("this sales order request.")
要 保持在一个块中,为翻译人员提供完整的上下文::
# good, allow to change position of the number in the translation
_("You have %s invoices wainting") % len(invoices)
_.str.sprintf(_t("You have %s invoices wainting"), invoices.length);
# good, full sentence is understandable
_("Reference of the document that generated " + \
"this sales order request.")
复数¶
不要 按照英语的方式对术语进行复数化::
msg = _("You have %(count)s invoice", count=invoice_count)
if invoice_count > 1:
msg += _("s")
要 记住每种语言都有不同的复数形式::
if invoice_count > 1:
msg = _("You have %(count)s invoices", count=invoice_count)
else:
msg = _("You have one invoice")
读取时与运行时¶
不要 在服务器启动时调用翻译查找::
ERROR_MESSAGE = {
# bad, evaluated at server launch with no user language
'access_error': _('Access Error'),
'missing_error': _('Missing Record'),
}
class Record(models.Model):
def _raise_error(self, code):
raise UserError(ERROR_MESSAGE[code])
不要 在读取JavaScript文件时调用翻译查找::
# bad, js _t is evaluated too early
var core = require('web.core');
var _t = core._t;
var map_title = {
access_error: _t('Access Error'),
missing_error: _t('Missing Record'),
};
要 使用惰性翻译查找方法::
ERROR_MESSAGE = {
'access_error': _lt('Access Error'),
'missing_error': _lt('Missing Record'),
}
class Record(models.Model):
def _raise_error(self, code):
# translation lookup executed at error rendering
raise UserError(ERROR_MESSAGE[code])
或者要 动态评估可翻译内容::
# good, evaluated at run time
def _get_error_message(self):
return {
access_error: _('Access Error'),
missing_error: _('Missing Record'),
}
要 在读取JS文件时执行翻译查找的情况下,使用 _lt
而不是 _t
,以便在术语被 使用 时进行翻译::
# good, js _lt is evaluated lazily
var core = require('web.core');
var _lt = core._lt;
var map_title = {
access_error: _lt('Access Error'),
missing_error: _lt('Missing Record'),
};