翻译模块

本节介绍如何为您的模块提供翻译功能。

注解

如果您想为 Odoo 本身的翻译做出贡献,请参阅 Odoo Wiki page

导出可翻译术语

模块中的许多术语都是隐式可翻译的。因此,即使您没有完成任何特定的翻译工作,您也可以导出模块的可翻译术语,并可能找到可以使用的内容。

翻译导出是通过管理界面执行的,方法是登录后端界面并打开 Settings ‣ Translations ‣ Import / Export ‣ Export Translations

  • 将语言保留为默认值(新语言/空模板)

  • 选择 PO File 格式

  • 选择您的模块

  • 单击 Export 并下载文件

../../_images/po-export.png

这将为您提供一个名为 yourmodule.pot 的文件,应将其移动到 yourmodule/i18n/ 目录。该文件是一个 PO 模板,它仅列出可翻译的字符串,并可以从中创建实际的翻译(PO 文件)。 PO 文件可以使用 msginitPOEdit 等专用翻译工具来创建,或者只需将模板复制到名为 language.po 的新文件即可。翻译文件应放在 yourmodule/i18n/ 中,紧邻 yourmodule.pot,当安装相应语言时,Odoo 会自动加载(通过 Settings ‣ Translations ‣ Languages

注解

安装或更新模块时也会安装或更新所有加载语言的翻译

隐性出口

Odoo 自动从“数据”类型内容导出可翻译字符串:

  • 在非 QWeb 视图中,将导出所有文本节点以及 string, help, sum, confirm and placeholder 属性的内容

  • QWeb 模板(服务器端和客户端),除了 t-translation="off" blocks, the content of the title, alt, label and placeholder 属性之外的所有文本节点都被导出

  • 对于 Field,除非其型号标有“_translate = False”:

    • 他们的``string`` and ``help``属性被导出

    • 如果存在“selection”并且是一个列表(或元组),则将其导出

    • 如果它们的``translate`` attribute is set to True,则导出它们的所有现有值(跨所有记录)

显式导出

当涉及到 Python 代码或 Javascript 代码中更“必要”的情况时,Odoo 无法自动导出可翻译术语,因此必须明确标记它们以供导出。这是通过在函数调用中包装文字字符串来完成的。

在Python中,包装函数是:func:odoo.api.Environment._`和:func:`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_salewebsite_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._`, the language and the module are extracted from the context. For this, we inspect the caller’s local variables. The drawback of this method is that it is error-prone: we try to find the context variable or ``self.env`”,如果您在模型方法之外使用翻译,则这些可能不存在;即它不能在常规函数或 python 推导式中工作。

惰性翻译在创建期间绑定到模块,并且在使用“str()`. Note that you can also pass a lazy translation to ``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 waiting") % len(invoices)
_.str.sprintf(_t("You have %s invoices waiting"), 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])

do 动态评估可翻译内容:

# 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'),
};