翻譯模塊?
本節將介紹如何為您的模塊提供翻譯功能。
注解
如果您想為Odoo本身的翻譯做出貢獻,請參考 `Odoo Wiki頁面<https://github.com/odoo/odoo/wiki/Translations>`_。
導出可翻譯術語?
你的模塊中有許多術語是“隱式可翻譯的”,因此,即使你沒有進行任何特定的翻譯工作,你也可以導出你的模塊可翻譯的術語,并找到需要處理的內容。
通過登錄后臺界面并打開
,可以通過管理界面執行翻譯導出操作。將語言保留為默認值(新語言/空模板)
選擇 PO 文件 格式
選擇您的模塊
點擊 導出 并下載文件

這將會生成一個名為 yourmodule.pot
的文件,需要將其移動到 yourmodule/i18n/
目錄下。該文件是一個 PO 模板 ,僅列出可翻譯的字符串,并可用于創建實際的翻譯文件(PO 文件)??梢允褂?msginit 創建 PO 文件,也可以使用專用的翻譯工具如 POEdit,或者簡單地將模板復制到一個名為 language.po
的新文件中。翻譯文件應該放在 yourmodule/i18n/
目錄下,與 yourmodule.pot
放在一起,當相應的語言被安裝時,Odoo 會自動加載它們 (通過 )
注解
在安裝或更新模塊時,所有已加載語言的翻譯也會被安裝或更新。
隱式導出?
Odoo會自動從“data”類型的內容中導出可翻譯的字符串:
在非 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._()
title = _("Bank Accounts")
在JavaScript中,通常使用 :js odoo.web._t()
函數進行包裝:
title = _t("Bank Accounts");
警告
只有字面字符串可以被標記為導出項,不能是表達式或變量。對于需要格式化的字符串,需要標記格式化字符串而不是格式化后的字符串。
_
和 _t
的懶惰版本是 Python 中的 odoo._lt()
和 JavaScript 中的 :js odoo.web._lt()
。翻譯查找僅在渲染時執行,可用于在類方法或全局變量中聲明可翻譯屬性。
注解
默認情況下,模塊的翻譯 不會 被公開到前端,因此無法從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']
變量?
不要這樣做 提取可能有效,但它將無法正確翻譯文本:
_("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")
讀取時間 vs 運行時間?
不要 在服務器啟動時調用翻譯查找:
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'),
};